HDU - 1540Tunnel Warfare(线段树 单点更新 区间查询)
2017-06-10 23:45
417 查看
HDU - 1540 题目链接
这一题看上去是单点查询,其实是查询区间啦,查询x左边的靠右的区间和右边的靠左的区间的和。
今天看了一篇博客,感觉说的真的很好,自己动不动就去翻discuss和题解真的挺不好的。
刷题是为了什么呢,又不是为了题量,而是为了自己的思维能力。思维能力上不去,写的题再多有什么用啊。
在这里立下flag,以后除非卡成10天半个月或更久过不了题,再去翻题解,翻题解也别看代码,主要是思路。这个毛病可能一时半会改不过来,但是一定是要改的。
今天的效率也低的吓人。决定以后早点睡了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
const int maxn = 5e4+10;
int n,m;
int f[maxn],sta[maxn << 2];
int lm[maxn << 2], rm[maxn << 2];
int slen = 0;
void build(int l,int r,int id)
{
lm[id] = rm[id ] = r-l+1;
if(l == r) { return;}
int m = l+r>>1;
build(l,m,id<<1);
build(m+1,r,id<<1|1);
}
void up(int ti,int id,int way,int l,int r)
{
if(ti < l || ti > r) return;
if(ti == l && l == r){lm[id] = rm[id] = way; return;}
int m = l+r>>1;
if(ti <= m) up(ti,id<<1,way,l,m);
else up(ti,id<<1|1,way,m+1,r);
lm[id] = lm[id<<1]; rm[id] = rm[id<<1|1];
if(lm[id<<1] == (m-l+1)) lm[id] += lm[id<<1|1];
if(rm[id<<1|1] == (r-m)) rm[id] += rm[id<<1];
}
int q1(int ql,int qr,int id,int l,int r)
{
if(qr < l || ql > r) return 0;
if(l >= ql && r <= qr){return rm[id];}
int m = l+r>>1;
if(qr <= m) return q1(ql,qr,id<<1,l,m);
else if(ql > m) return q1(ql,qr,id<<1|1,m+1,r);
else
{
int ans = min(qr-m,q1(ql,qr,id<<1|1,m+1,r));
if(ans >= (qr-m)) ans += min(m-ql+1,q1(ql,qr,id<<1,l,m));
return ans;
}
}
int q(int ql,int qr,int id,int l,int r)
{
if(l >= ql && r <= qr){return lm[id];}
int m = l+r>>1;
if(qr <= m) return q(ql,qr,id<<1,l,m);
else if(ql > m) return q(ql,qr,id<<1|1,m+1,r);
else
{
int ans = min(m-ql+1,q(ql,qr,id<<1,l,m));
if(ans >= (m-ql+1)) ans += min(qr-m,q(ql,qr,id<<1|1,m+1,r));
return ans;
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
slen = 0;
met(f,0);
met(sta,0);
build(1,n,1);
for(int i = 0; i < m ; i++)
{
char s[3]; int a;
scanf("%s",s);
if(s[0] == 'R')
{
if(slen != 0)
{
int t = sta[--slen];
if(f[t]){ f[t] = 0; up(t,1,1,1,n); }
}
}
else
{
scanf("%d",&a);
if(s[0] == 'D'){sta[slen ++] = a; if(!f[a]){up(a,1,0,1,n); f[a] = 1;}}
else
{
if(!f[a])
{
int ans = 1,l = 0,r = 0;
if(a > 1) l += q1(1, a-1, 1, 1,n);
if(a < n) r += q(a+1, n, 1, 1, n);
printf("%d\n",ans+l+r);
}
else printf("0\n");
}
}
}
}
return 0;
}
这一题看上去是单点查询,其实是查询区间啦,查询x左边的靠右的区间和右边的靠左的区间的和。
今天看了一篇博客,感觉说的真的很好,自己动不动就去翻discuss和题解真的挺不好的。
刷题是为了什么呢,又不是为了题量,而是为了自己的思维能力。思维能力上不去,写的题再多有什么用啊。
在这里立下flag,以后除非卡成10天半个月或更久过不了题,再去翻题解,翻题解也别看代码,主要是思路。这个毛病可能一时半会改不过来,但是一定是要改的。
今天的效率也低的吓人。决定以后早点睡了。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define met(a,b) memset(a,b,sizeof(a))
const int maxn = 5e4+10;
int n,m;
int f[maxn],sta[maxn << 2];
int lm[maxn << 2], rm[maxn << 2];
int slen = 0;
void build(int l,int r,int id)
{
lm[id] = rm[id ] = r-l+1;
if(l == r) { return;}
int m = l+r>>1;
build(l,m,id<<1);
build(m+1,r,id<<1|1);
}
void up(int ti,int id,int way,int l,int r)
{
if(ti < l || ti > r) return;
if(ti == l && l == r){lm[id] = rm[id] = way; return;}
int m = l+r>>1;
if(ti <= m) up(ti,id<<1,way,l,m);
else up(ti,id<<1|1,way,m+1,r);
lm[id] = lm[id<<1]; rm[id] = rm[id<<1|1];
if(lm[id<<1] == (m-l+1)) lm[id] += lm[id<<1|1];
if(rm[id<<1|1] == (r-m)) rm[id] += rm[id<<1];
}
int q1(int ql,int qr,int id,int l,int r)
{
if(qr < l || ql > r) return 0;
if(l >= ql && r <= qr){return rm[id];}
int m = l+r>>1;
if(qr <= m) return q1(ql,qr,id<<1,l,m);
else if(ql > m) return q1(ql,qr,id<<1|1,m+1,r);
else
{
int ans = min(qr-m,q1(ql,qr,id<<1|1,m+1,r));
if(ans >= (qr-m)) ans += min(m-ql+1,q1(ql,qr,id<<1,l,m));
return ans;
}
}
int q(int ql,int qr,int id,int l,int r)
{
if(l >= ql && r <= qr){return lm[id];}
int m = l+r>>1;
if(qr <= m) return q(ql,qr,id<<1,l,m);
else if(ql > m) return q(ql,qr,id<<1|1,m+1,r);
else
{
int ans = min(m-ql+1,q(ql,qr,id<<1,l,m));
if(ans >= (m-ql+1)) ans += min(qr-m,q(ql,qr,id<<1|1,m+1,r));
return ans;
}
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
slen = 0;
met(f,0);
met(sta,0);
build(1,n,1);
for(int i = 0; i < m ; i++)
{
char s[3]; int a;
scanf("%s",s);
if(s[0] == 'R')
{
if(slen != 0)
{
int t = sta[--slen];
if(f[t]){ f[t] = 0; up(t,1,1,1,n); }
}
}
else
{
scanf("%d",&a);
if(s[0] == 'D'){sta[slen ++] = a; if(!f[a]){up(a,1,0,1,n); f[a] = 1;}}
else
{
if(!f[a])
{
int ans = 1,l = 0,r = 0;
if(a > 1) l += q1(1, a-1, 1, 1,n);
if(a < n) r += q(a+1, n, 1, 1, n);
printf("%d\n",ans+l+r);
}
else printf("0\n");
}
}
}
}
return 0;
}
相关文章推荐
- hdu 1540 Tunnel Warfare 线段树 单点更新,查询区间长度,区间合并
- HDU 1540——Tunnel Warfare(线段树,区间合并+单点更新+单点查询)
- hdu 1540 Tunnel Warfare 线段树 单点更新,查询区间长度,区间合并
- POJ 2892 Tunnel Warfare || HDU 1540(树状数组+二分 || 线段树的单点更新+区间查询)
- HDU 1540 Tunnel Warfare(线段树单点更新+区间合并)
- 【HDU - 1540】Tunnel Warfare 【线段树+单点更新+区间合并】
- HDU 1540 Tunnel Warfare(线段树 区间合并 +单点更新)
- hdu 1540 Tunnel Warfare(线段树单点更新+区间合并)
- HDU 1556 给连续个球涂色-线段树-(区间更新,单点查询)
- hdu 5480 Conturbatio 线段树 单点更新,区间查询最小值
- HDU 2795 线段树(单点更新 区间查询)
- HDU1754线段树单点更新区间查询(数组版)
- POJ 题目2892 Tunnel Warfare(线段树单点更新查询,求单点所在最大连续区间长度)
- HDU-1556-Color the ball-线段树+区间更新+单点查询
- hdu 1166 敌兵布阵(线段树单点更新,区间查询)
- HDU 3308 线段树 最长连续上升子序列 单点更新 区间查询
- 线段树 单点更新查询 区间最大值 hdu 2795 Billboard
- HDU 3874 Necklace (线段树单点更新+区间查询+离线操作)
- hdu 1540 Tunnel Warfare(单点更新,区间合并)
- hdu 4046 Panda (线段树 单点更新 区间查询)