hdu 1166 敌兵布阵
操作:单点增加或减少,查询区间和.
http://acm.hdu.edu.cn/showproblem.php?pid=1166
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int inf=0x3f3f3f3f;
- const int maxn=50010;
- struct ST
- {
- int l,r;
- int sum;
- }st[maxn<<2];
- void pushUp(int i)
- {
- st[i].sum=st[i<<1].sum+st[(i<<1)|1].sum;
- }
- void build(int i,int l,int r)
- {
- st[i].l=l;
- st[i].r=r;
- if(st[i].l==st[i].r)
- {
- rd(st[i].sum);
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- pushUp(i);
- }
- void add(int i,int p,int val)
- {
- if(st[i].l==st[i].r)
- {
- st[i].sum+=val;
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(p<=mid)
- add(i<<1,p,val);
- else
- add((i<<1)|1,p,val);
- pushUp(i);
- }
- int query(int i,int L,int R)
- {
- if(st[i].l==L&&st[i].r==R)
- {
- return st[i].sum;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(R<=mid)
- return query(i<<1,L,R);
- else if(L>mid)
- return query((i<<1)|1,L,R);
- else
- return query(i<<1,L,mid)+query((i<<1)|1,mid+1,R);
- }
- int n;
- char cm[10];
- int main()
- {
- int cas=1;
- int t;rd(t);
- while(t--)
- {
- printf("Case %d:\n",cas++);
- rd(n);
- build(1,1,n);
- while(scanf("%s",cm))
- {
- if(cm[0]=='Q')
- {
- int l,r;
- rd2(l,r);
- printf("%d\n",query(1,l,r));
- }
- else if(cm[0]=='A')
- {
- int p,val;
- rd2(p,val);
- add(1,p,val);
- }
- else if(cm[0]=='S')
- {
- int p,val;
- rd2(p,val);
- add(1,p,-val);
- }
- else
- break;
- }
- }
- return 0;
- }
hdu 1754 I hate it
http://acm.hdu.edu.cn/showproblem.php?pid=1754
操作:单点替换为另一个值,查询区间最大值.
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int inf=0x3f3f3f3f;
- const int maxn=200010;
- struct ST
- {
- int l,r;
- int MAX;
- }st[maxn<<2];
- void pushUp(int i)
- {
- st[i].MAX=max(st[i<<1].MAX,st[(i<<1)|1].MAX);
- }
- void build(int i,int l,int r)
- {
- st[i].l=l;
- st[i].r=r;
- if(st[i].l==st[i].r)
- {
- rd(st[i].MAX);
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- pushUp(i);
- }
- void update(int i,int p,int val)
- {
- if(st[i].l==st[i].r)
- {
- st[i].MAX=val;
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(p<=mid)
- update(i<<1,p,val);
- else
- update((i<<1)|1,p,val);
- pushUp(i);
- }
- int query(int i,int L,int R)
- {
- if(st[i].l==L&&st[i].r==R)
- {
- return st[i].MAX;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(R<=mid)
- return query(i<<1,L,R);
- else if(L>mid)
- return query((i<<1)|1,L,R);
- else
- return max(query(i<<1,L,mid),query((i<<1)|1,mid+1,R));
- }
- int n,m;
- char cm[5];
- int main()
- {
- while(rd2(n,m)!=EOF)
- {
- build(1,1,n);
- while(m--)
- {
- scanf("%s",cm);
- if(cm[0]=='Q')
- {
- int l,r;
- rd2(l,r);
- printf("%d\n",query(1,l,r));
- }
- else
- {
- int p,val;
- rd2(p,val);
- update(1,p,val);
- }
- }
- }
- return 0;
- }
poj 3468 A Simple Problem with Integers
http://poj.org/problem?id=3468
操作:区间的每个值都增加一个数,查询区间总和。
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int maxn=100010;
- struct ST
- {
- int l,r;
- ll lazy;
- ll sum;
- }st[maxn<<2];
- void pushUp(int i)
- {
- st[i].sum=st[i<<1].sum+st[(i<<1)|1].sum;
- }
- void pushDown(int i,int len)
- {
- if(st[i].lazy!=0)
- {
- st[i<<1].lazy+=st[i].lazy;
- st[(i<<1)|1].lazy+=st[i].lazy;
- st[i<<1].sum+=(long long)(len-(len>>1))*st[i].lazy;
- st[(i<<1)|1].sum+=(long long)(len>>1)*st[i].lazy;
- st[i].lazy=0;
- }
- }
- void build(int i,int l,int r)
- {
- st[i].l=l;
- st[i].r=r;
- st[i].lazy=0;
- if(st[i].l==st[i].r)
- {
- scanf("%I64d",&st[i].sum);
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- pushUp(i);
- }
- void add(int i,int L,int R,int val)
- {
- if(st[i].l==L&&st[i].r==R)
- {
- st[i].sum+=(long long)(st[i].r-st[i].l+1)*val;
- st[i].lazy+=val;
- return;
- }
- pushDown(i,st[i].r-st[i].l+1);
- int mid=(st[i].l+st[i].r)>>1;
- if(R<=mid)
- add(i<<1,L,R,val);
- else if(L>mid)
- add((i<<1)|1,L,R,val);
- else
- {
- add(i<<1,L,mid,val);
- add((i<<1)|1,mid+1,R,val);
- }
- pushUp(i);
- }
- ll query(int i,int L,int R)
- {
- if(st[i].l==L&&st[i].r==R)
- {
- return st[i].sum;
- }
- pushDown(i,st[i].r-st[i].l+1);
- int mid=(st[i].l+st[i].r)>>1;
- if(R<=mid)
- return query(i<<1,L,R);
- else if(L>mid)
- return query((i<<1)|1,L,R);
- else
- return query(i<<1,L,mid)+query((i<<1)|1,mid+1,R);
- }
- int n,q;
- int l,r,val;
- char cm;
- int main()
- {
- while(scanf("%d%d",&n,&q)!=EOF)
- {
- build(1,1,n);
- while(q--)
- {
- scanf("%s",&cm);
- if(cm=='C')
- {
- scanf("%d%d%d",&l,&r,&val);
- add(1,l,r,val);
- }
- else
- {
- scanf("%d%d",&l,&r);
- printf("%I64d\n",query(1,l,r));
- }
- }
- }
- return 0;
- }
hdu 1698 just a hook
http://acm.hdu.edu.cn/showproblem.php?pid=1698
操作:指定区间每个值修改为另一个值,求总区间总和。
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int maxn=100010;
- struct ST
- {
- int l,r;
- int lazy;
- int sum;
- }st[maxn<<2];
- void pushUp(int i)
- {
- st[i].sum=st[i<<1].sum+st[(i<<1)|1].sum;
- }
- void pushDown(int i,int len)
- {
- if(st[i].lazy!=0)
- {
- st[i<<1].lazy=st[(i<<1)|1].lazy=st[i].lazy;
- st[i<<1].sum=(len-(len>>1))*st[i].lazy;
- st[(i<<1)|1].sum=(len>>1)*st[i].lazy;
- st[i].lazy=0;
- }
- }
- void build(int i,int l,int r)
- {
- st[i].l=l;
- st[i].r=r;
- st[i].lazy=0;
- if(st[i].l==st[i].r)
- {
- st[i].sum=1;
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- pushUp(i);
- }
- void update(int i,int l,int r,int val)
- {
- if(st[i].l==l&&st[i].r==r)
- {
- st[i].sum=(st[i].r-st[i].l+1)*val;
- st[i].lazy=val;
- return;
- }
- pushDown(i,st[i].r-st[i].l+1);
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- update(i<<1,l,r,val);
- else if(l>mid)
- update((i<<1)|1,l,r,val);
- else
- {
- update(i<<1,l,mid,val);
- update((i<<1)|1,mid+1,r,val);
- }
- pushUp(i);
- }
- int t,n,q;
- int l,r,val;
- int cas=1;
- int main()
- {
- rd(t);
- while(t--)
- {
- rd(n);
- rd(q);
- build(1,1,n);
- while(q--)
- {
- rd3(l,r,val);
- update(1,l,r,val);
- }
- printf("Case %d: The total value of the hook is %d.\n",cas++,st[1].sum);
- }
- return 0;
- }
poj 2528 Mayor's posters
http://poj.org/problem?id=2528
有一条1到10000000的线段,然后给指定区间涂颜色,制定区间个数最多为10000个,后面的颜色覆盖前面的颜色,问最后涂完一共可以看见几种颜色。
要用到离散化,比如 [1, 10000] [2, 99999999] [10000,20000]这三个区间
端点从小到大排序并去重后得到
1 2 10000 20000 99999999 分别映射到数字 1 2 3 4 5,也就是1->1 2->2 10000->3 20000->4 99999999->5
那么给定的区间就可以变为[1,3] [2,5] [3,4] ,原覆盖关系没变,这样区间长度就大大缩短了
但这样容易出错 比如 [1,10] [1,4] [6,10] 这组数据,答案应该是3, 但是像前面那样处理后,区间变为[1,4] [1,2] [3,4] ,答案是2,处理方法为
端点从小到大排序并去重得到1 4 6 10 ,对于相邻两个数如果差距大于1,那么就再里面随便加上一个数,变为 1 (2) 4 (5) 6 (7) 10
然后映射关系为1->1 2->2 4->3 5->4 6->5 7->6 10->7
那么原区间就变为[1,7] [ 1,3] [5,7] ,答案正确为3
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int inf=0x3f3f3f3f;
- const int maxn=10010;
- int id[10000005];//离散化以后对应的id,原区间为l,r,离散化后变为id[l],id[r]
- int t;
- int n;
- int x[maxn*3];//4倍的,2倍是一条线段两个端点,1倍是两个端点之间再加一个,就像[1,10] [1,4] [6,10]这样的数据防止错误
- struct ST
- {
- int l,r;
- int covered;
- }st[maxn*16];//要开线段长度的4倍,按理说12就可以,但是re,开了13就可以,迷糊.....
- struct poster
- {
- int l,r;
- }post[maxn];
- void build(int i,int l,int r)
- {
- st[i].l=l;
- st[i].r=r;
- st[i].covered=false;//一开始都是没被覆盖
- if(st[i].l==st[i].r)
- return;
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- }
- bool isvisible(int i,int l,int r)
- {
- if(st[i].covered==true)//如果该节点代表的区间已被覆盖掉,直接返回
- return false;
- if(st[i].l==l&&st[i].r==r)//找到那一段区间
- {
- st[i].covered=true;
- return true;
- }
- bool ok;
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- ok=isvisible(i<<1,l,r);
- else if(l>mid)
- ok=isvisible((i<<1)|1,l,r);
- else
- {
- bool a=isvisible(i<<1,l,mid);//左一半区间是否被覆盖
- bool b=isvisible((i<<1)|1,mid+1,r);//有一半
- ok=a||b;//有一个为真,Ok就为真,为真代表没有被覆盖
- }
- if(st[i<<1].covered&&st[(i<<1)|1].covered)//向上更新
- st[i].covered=true;
- return ok;
- }
- int main()
- {
- rd(t);
- while(t--)
- {
- rd(n);
- int len=0;
- for(int i=1;i<=n;i++)
- {
- rd2(post[i].l,post[i].r);
- x[len++]=post[i].l;
- x[len++]=post[i].r;
- }
- sort(x,x+len);
- len=unique(x,x+len)-x;//去掉重复
- int tp=len;
- for(int i=1;i<tp;i++)
- {
- if(x[i]-x[i-1]>1)
- x[len++]=x[i-1]+1;//避免 [1,10] [1,4] [6,10]这样的数据
- }
- sort(x,x+len);
- for(int i=0;i<len;i++)
- {
- id[x[i]]=i+1;
- }
- build(1,1,len);
- int ans=0;
- for(int i=n;i>=1;i--)
- {
- if(isvisible(1,id[post[i].l],id[post[i].r]))
- ans++;
- }
- printf("%d\n",ans);
- }
- return 0;
- }
zoj 1610 Count the Colors
http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1610
在一条线段上染色,颜色的种类用数字表示,后染色的覆盖前面的染色,问最后能看到几种颜色,且每种颜色有多少不连续的段。比如 [1,8]先染成白色,[1,2]再染成红色,[5,8]再染成红色,那么可以看到白色的有一段(中间),红色的有两段。 题目中所有涉及的数的范围都为[0,8000]。
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int inf=0x3f3f3f3f;
- const int maxn=8010;
- int color[maxn];//每个点的颜色
- int ans[maxn];//输出的
- struct ST
- {
- int l,r;
- int flag;//代表的颜色,默认-1
- }st[maxn<<2];
- void pushUp(int i)
- {
- if(st[i<<1].flag==st[(i<<1)|1].flag&&st[i<<1].flag!=-1)
- st[i].flag=st[i<<1].flag;
- }
- void pushDown(int i)
- {
- if(st[i].flag!=-1)
- {
- st[i<<1].flag=st[i].flag;
- st[(i<<1)|1].flag=st[i].flag;
- st[i].flag=-1;//这里是-1,其实是混合色
- }
- }
- void build(int i,int l,int r)
- {
- st[i].l=l;
- st[i].r=r;
- st[i].flag=-1;
- if(st[i].l==st[i].r)
- return;
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- }
- void update(int i,int l,int r,int val)
- {
- if(st[i].flag==val)
- return;
- if(l<=st[i].l&&st[i].r<=r)//因为参数l,r是整个染色的区间,下面的递归也是整个染色的区间,用[1,9]建立线段树,给[1,8]染色模拟一遍就懂了
- {
- st[i].flag=val;
- return;
- }
- pushDown(i);
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- update(i<<1,l,r,val);
- else if(l>mid)
- update((i<<1)|1,l,r,val);
- else
- {
- update(i<<1,l,r,val);
- update((i<<1)|1,l,r,val);
- }
- pushUp(i);
- }
- void query(int i)
- {
- if(st[i].flag!=-1)
- {
- for(int j=st[i].l;j<=st[i].r;j++)
- color[j]=st[i].flag;
- return;
- }
- if(st[i].l==st[i].r)//父节点的flag-1,那么子节点的flag有可能-1,也有可能不是-1,加这一句话是-1的情况,没有染色
- return;
- query(i<<1);
- query((i<<1)|1);
- }
- int n,N=8000;
- int l,r,val;
- int main()
- {
- while(rd(n)!=EOF)
- {
- build(1,0,N);
- memset(color,-1,sizeof(color));
- memset(ans,0,sizeof(ans));
- while(n--)
- {
- rd3(l,r,val);
- update(1,l,r-1,val);//为了避免 [1,2] [3,4]这样的情况,如果是相同的颜色,那么应该是两段[2,3]是空白
- }
- query(1);
- int pre=-1;
- for(int i=0;i<N;i++)
- {
- if(pre!=color[i])
- {
- pre=color[i];
- if(pre==-1)
- continue;
- ans[color[i]]++;
- }
- }
- for(int i=0;i<N;i++)
- if(ans[i])
- printf("%d %d\n",i,ans[i]);
- printf("\n");
- }
- return 0;
- }
poj 3264 Balanced Lineup
http://poj.org/problem?id=3264
求区间内最大值与最小值的差。
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int inf=0x3f3f3f3f;
- const int maxn=50010;
- struct ST
- {
- int l,r;
- int MAX,MIN;
- }st[maxn<<2];
- void pushUp(int i)
- {
- st[i].MAX=max(st[i<<1].MAX,st[(i<<1)|1].MAX);
- st[i].MIN=min(st[i<<1].MIN,st[(i<<1)|1].MIN);
- }
- void build(int i,int l,int r)
- {
- st[i].l=l;
- st[i].r=r;
- if(st[i].l==st[i].r)
- {
- rd(st[i].MAX);
- st[i].MIN=st[i].MAX;
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- pushUp(i);
- }
- int query1(int i,int l,int r)
- {
- if(st[i].l==l&&st[i].r==r)
- {
- return st[i].MAX;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- return query1(i<<1,l,r);
- else if(l>mid)
- return query1((i<<1)|1,l,r);
- else
- {
- return max(query1(i<<1,l,mid),query1((i<<1)|1,mid+1,r));
- }
- }
- int query2(int i,int l,int r)
- {
- if(st[i].l==l&&st[i].r==r)
- {
- return st[i].MIN;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- return query2(i<<1,l,r);
- else if(l>mid)
- return query2((i<<1)|1,l,r);
- else
- {
- return min(query2(i<<1,l,mid),query2((i<<1)|1,mid+1,r));
- }
- }
- int MAX,MIN;
- void query(int i,int l,int r)
- {
- if(st[i].MAX<MAX&&st[i].MIN>MIN)
- return;
- if(st[i].l==l&&st[i].r==r)
- {
- MAX=max(st[i].MAX,MAX);
- MIN=min(st[i].MIN,MIN);
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- query(i<<1,l,r);
- else if(l>mid)
- query((i<<1)|1,l,r);
- else
- {
- query(i<<1,l,mid);
- query((i<<1)|1,mid+1,r);
- }
- }
- int n,q;
- int l,r;
- int main()
- {
- while(rd2(n,q)!=EOF)
- {
- build(1,1,n);
- while(q--)
- {
- rd2(l,r);
- MAX=-1,MIN=1000002;
- // printf("%d\n",query1(1,l,r)-query2(1,l,r));这个也可以
- query(1,l,r);
- printf("%d\n",MAX-MIN);
- }
- }
- return 0;
- }
hdu 4027 Can you answer these queries?
http://acm.hdu.edu.cn/showproblem.php?pid=4027
操作:给定区间,将区间内的每个值都变为原来的平方根(去整),查询区间和。long long
当一个数为0或者为1时,该数就不用再被更新了,用allone表示该数或者该区间是否需要更新,当allone==1是,表示不用更新,碰到该节点,直接返回就可以。
题目给出的区间端点x,y,没有说明x<=y,得判断一下.....
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int inf=0x3f3f3f3f;
- const int maxn=100010;
- struct ST
- {
- int l,r;
- ll sum;
- bool allone;
- }st[maxn<<2];
- void pushUp(int i)
- {
- st[i].sum=st[i<<1].sum+st[(i<<1)|1].sum;
- st[i].allone=st[i<<1].allone&&st[(i<<1)|1].allone;
- }
- void build(int i,int l,int r)
- {
- st[i].l=l;
- st[i].r=r;
- if(st[i].l==st[i].r)
- {
- scanf("%I64d",&st[i].sum);
- if(st[i].sum==0||st[i].sum==1)
- st[i].allone=1;
- else
- st[i].allone=0;
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- pushUp(i);
- }
- void cal(int i,int l,int r)
- {
- //if(st[i].sum==(st[i].r-st[i].l+1))//数据中如果每个endurance值不为0的话可以这样判断,这个区间每个点都为1,就不用再更新
- // return;
- if(st[i].allone==1)//该区间内全是1,不用再更新了
- return;
- if(st[i].l==st[i].r)//找到该数
- {
- st[i].sum=(ll)sqrt(1.0*st[i].sum);
- if(st[i].sum==1)
- st[i].allone=1;
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- cal(i<<1,l,r);
- else if(l>mid)
- cal((i<<1)|1,l,r);
- else
- {
- cal(i<<1,l,mid);
- cal((i<<1)|1,mid+1,r);
- }
- pushUp(i);
- }
- ll query(int i,int l,int r)
- {
- if(st[i].l==l&&st[i].r==r)
- {
- return st[i].sum;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- return query(i<<1,l,r);
- else if(l>mid)
- return query((i<<1)|1,l,r);
- else
- {
- return query(i<<1,l,mid)+query((i<<1)|1,mid+1,r);
- }
- }
- int n,q;
- int cm,l,r;
- int c=1;
- int main()
- {
- while(rd(n)!=EOF)
- {
- printf("Case #%d:\n",c++);
- build(1,1,n);
- rd(q);
- while(q--)
- {
- rd3(cm,l,r);
- if(l>r)
- swap(l,r);//陷阱!
- if(!cm)
- {
- cal(1,l,r);
- }
- else
- printf("%I64d\n",query(1,l,r));
- }
- printf("\n");
- }
- return 0;
- }
poj 2892 Tunnel Warfare
http://poj.org/problem?id=2892
一开始有连续的n个1,位置分别是1-n,三种操作,一是将某个位置的1变为0,而是将某个位置的0修复为1,三是查询包含某个位置的最大连续区间(该区间内都是1)的长度.
样例
7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4
一开始7个位置全是1, 1 1 1 1 1 1 1, D 3表示将第3个位置设为0,即 1 1 0 1 1 1 1,D 6, 1 1 0 1 1 0 1,D 5 , 1 1 0 1 0 0 1,
Q 4表示查询包含位置4的最大连续区间(全为1), 答案为1,Q 5答案为0, 都是在 1 1 0 1 0 0 1中看出来的
R表示将最后一个设为0的位置修复为1,也就是将第5个位置修复为1 , 即 1 1 0 1 1 0 1,Q 4 ,答案为2
再一个R表示将第6个位置修复为1,1 1 0 1 1 1 1,Q4, 答案为4
想法在注释中。
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int inf=0x3f3f3f3f;
- const int maxn=50010;
- struct ST
- {
- int l,r;
- int ls,rs,ms;//区间左端多少个连续1,右端多少个连续1,该区间最大连续1长多少,即左端连续区间,右端连续区间,最大连续区间
- }st[maxn<<2];
- void build(int i,int l,int r)
- {
- st[i].l=l;
- st[i].r=r;
- if(st[i].l==st[i].r)
- {
- st[i].ls=1;st[i].rs=1;st[i].ms=1;
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- st[i].ls=st[i].rs=st[i].ms=st[i].r-st[i].l+1;
- }
- void update(int i,int p,char c)//位置为p,命令为c
- {
- if(st[i].l==st[i].r)
- {
- if(c=='D')//破坏
- st[i].ls=st[i].rs=st[i].ms=0;
- else//修复
- st[i].ls=st[i].rs=st[i].ms=1;
- return;
- }
- int mid=(st[i].l+st[i].r)>>1;
- if(p<=mid)
- update(i<<1,p,c);
- else
- update((i<<1)|1,p,c);
- st[i].ls=st[i<<1].ls;//孩子节点左连续区间肯定是父节点的左端连续区间的一部分
- st[i].rs=st[(i<<1)|1].rs;//右连续区间
- st[i].ms=max(max(st[i<<1].ms,st[(i<<1)|1].ms),st[i<<1].rs+st[(i<<1)|1].ls);
- //父亲节点的最大连续区间为 左孩子最大连续区间,右孩子最大连续区间,中间连续最大区间三者中的最大值
- //如果左孩子都是连续区间,那么父节点的左连续区间除了左孩子的左连续区间,还要加上右孩子的左连续区间
- if(st[i<<1].ls==st[i<<1].r-st[i<<1].l+1)
- {
- st[i].ls+=st[(i<<1)|1].ls;
- }
- //如果右孩子都是连续区间,那么父节点的右连续区间除了右孩子的右连续区间,还要加上左孩子的右连续区间
- if(st[(i<<1)|1].rs==st[(i<<1)|1].r-st[(i<<1)|1].l+1)
- {
- st[i].rs+=st[i<<1].rs;
- }
- }
- int query(int i,int p)
- {
- //该区间没有1或者找到该位置或者该区间全是1
- if(st[i].ms==0||st[i].l==st[i].r||st[i].ms==st[i].r-st[i].l+1)
- return st[i].ms;
- int mid=(st[i].l+st[i].r)>>1;
- if(p<=mid)//向左孩子中查询
- {
- if(p>=st[i<<1].r-st[i<<1].rs+1) //st[i<<1].r-st[i<<1].rs+1为左孩子节点右连续区间的左边界,比如[6,8]的长度为3,那么左边界就为8-3+1=6
- return query(i<<1,p)+query((i<<1)|1,mid+1);
- else
- return query(i<<1,p);
- //如果位置p在左孩子节点的右连续区间中,那么还要加上右孩子节点的左连续区间
- //比如左孩子[1,4],其右连续区间为[2,4],右孩子节点为[5,7],右孩子左连续区间为[5,6],位置p为3,那么包括3的连续区间不仅在[2,4]中,
- //还在[5,6]中,即包括3的最大连续区间为[2,6]
- }
- else//在右孩子中查询
- {
- if(p<=st[(i<<1)|1].l+st[(i<<1)|1].ls-1)
- return query((i<<1)|1,p)+query(i<<1,mid);
- else
- return query((i<<1)|1,p);
- //如果位置p在右孩子节点的左连续区间中,还要加上左孩子节点的右连续区间
- }
- }
- int n,m,p;
- char cm[2];
- stack<int>sta;
- int main()
- {
- while(rd2(n,m)!=EOF)
- {
- while(!sta.empty())
- sta.pop();
- build(1,1,n);
- while(m--)
- {
- scanf("%s",cm);
- if(cm[0]=='D')
- {
- rd(p);
- update(1,p,'D');
- sta.push(p);
- }
- else if(cm[0]=='R')
- {
- p=sta.top();
- sta.pop();
- update(1,p,'R');
- }
- else
- {
- rd(p);
- printf("%d\n",query(1,p));
- }
- }
- }
- return 0;
- }
hdu 3974 Assign the task
http://acm.hdu.edu.cn/showproblem.php?pid=3974
有n个员工,编号1-n,存在一些上司下属关系, a是c的上司,c是b的上司,那么a也是b的上司,没有上司的员工成为领导。给出n-1条上司下属关系,那么这n个员工关系就组成了一棵树,当给编号为i的员工分配任务时,该员工和其所有的下属都接受刚分配的任务,放弃前一个任务(如果有的话),查询编号为i的员工当前正做着哪一个任务。任务由数字表示。
在树中,父亲节点以及其所有的子节点是同时更新的,我们首先要把这些节点映射到区间上去,用dfs给这些点重新编号,start[i]表示该节点的新编号,end[i]表示其所有子节点的最后一个编号,那么执行更新操作时,只要对区间[start[i], end [i] ] 进行更新就可以了,把该区间的任务替换为新任务。
只要把树映射到线段区间上,就好操作了,建立线段树对其操作,区间更新,查询单点值,lazy表示分配的任务。
- #define rd(x) scanf("%d",&x)
- #define rd2(x,y) scanf("%d%d",&x,&y)
- #define rd3(x,y,z) scanf("%d%d%d",&x,&y,&z)
- using namespace std;
- typedef long long ll;
- const int inf=0x3f3f3f3f;
- const int maxn=50010;
- int number;//给节点编号
- int start[maxn],end[maxn];//第i个节点的编号,以及其孩子节点的最后一个编号,要更新,就更新这一段区间,对一个点操作,也就是对一段区间操作
- vector<int>vc[maxn];//邻接表存边
- void init()
- {
- number=0;
- for(int i=0;i<maxn;i++)
- vc[i].clear();
- }
- void dfs(int u)//编号
- {
- ++number;
- start[u]=number;
- int len=vc[u].size();
- for(int i=0;i<len;i++)
- {
- dfs(vc[u][i]);
- }
- end[u]=number;
- }
- struct ST
- {
- int l,r;
- int lazy;//分配的是什么任务
- }st[maxn<<2];
- void pushDown(int i)
- {
- if(st[i].lazy!=-1)
- {
- st[i<<1].lazy=st[(i<<1)|1].lazy=st[i].lazy;
- st[i].lazy=-1;
- }
- }
- void build(int i,int l,int r)
- {
- st[i].l=l;st[i].r=r;
- st[i].lazy=-1;
- if(st[i].l==st[i].r)
- return;
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- }
- void update(int i,int l,int r,int val)
- {
- if(st[i].l==l&&st[i].r==r)
- {
- st[i].lazy=val;
- return;
- }
- pushDown(i);
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- update(i<<1,l,r,val);
- else if(l>mid)
- update((i<<1)|1,l,r,val);
- else
- {
- update(i<<1,l,mid,val);
- update((i<<1)|1,mid+1,r,val);
- }
- }
- int query(int i,int p)
- {
- if(st[i].l==st[i].r)
- return st[i].lazy;
- pushDown(i);
- int mid=(st[i].l+st[i].r)>>1;
- if(p<=mid)
- return query(i<<1,p);
- else
- return query((i<<1)|1,p);
- }
- int n,m;
- char cm[2];
- int cas=1;
- int u,v;
- bool vis[maxn];
- int main()
- {
- int t;
- rd(t);
- while(t--)
- {
- printf("Case #%d:\n",cas++);
- rd(n);
- init();
- memset(vis,0,sizeof(vis));
- for(int i=1;i<n;i++)
- {
- rd2(u,v);
- vc[v].push_back(u);
- vis[u]=1;
- }
- for(int i=1;i<=n;i++)
- {
- if(!vis[i])//找到根节点,只有根节点没有被访问过
- {
- dfs(i);
- break;
- }
- }
- build(1,1,number);
- rd(m);
- while(m--)
- {
- scanf("%s",cm);
- if(cm[0]=='C')
- {
- rd(u);
- printf("%d\n",query(1,start[u]));//start[u]是该节点在线段中的编号
- }
- else
- {
- rd2(u,v);
- update(1,start[u],end[u],v);
- }
- }
- }
- return 0;
- }
sdut 2880 Devour Magic
http://www.sdutacm.org/sdutoj/problem.php?action=showproblem&problemid=2880
线段树操作:区间更新,总区间同时增加一个数,查询指定区间的和,查询后将该区间清0.
用到了两个lazy,一个是增量,一个是是否清0,Pushdown的时候,清0的lazy优先。
- #include <iostream>
- #include <stdio.h>
- #include <algorithm>
- #include <string.h>
- #include <stdlib.h>
- #include <cmath>
- #include <iomanip>
- #include <vector>
- #include <set>
- #include <map>
- #include <stack>
- #include <queue>
- #include <cctype>
- using namespace std;
- typedef long long ll;
- const int maxn=100010;
- struct ST
- {
- int l,r;
- ll sum;
- ll lazy;//懒惰标记
- ll lazy0;//该区间是否清0了
- }st[maxn<<2];
- void pushUp(int i)
- {
- st[i].sum=st[i<<1].sum+st[(i<<1)|1].sum;
- }
- void pushDown(int i,int len)
- {
- if(st[i].lazy0!=0)
- {
- st[i<<1].lazy0=st[(i<<1)|1].lazy0=st[i].lazy0;
- st[i<<1].sum=0;
- st[(i<<1)|1].sum=0;
- st[i<<1].lazy=0;
- st[(i<<1)|1].lazy=0;
- st[i].lazy0=0;
- }
- if(st[i].lazy!=0)
- {
- st[i<<1].lazy+=st[i].lazy;
- st[(i<<1)|1].lazy+=st[i].lazy;
- st[i<<1].sum+=ll(len-(len>>1))*st[i].lazy;
- st[(i<<1)|1].sum+=ll(len>>1)*st[i].lazy;
- st[i].lazy=0;
- }
- }
- void build(int i,int l,int r)
- {
- st[i].l=l;st[i].r=r;
- st[i].lazy=st[i].lazy0=0;
- st[i].sum=0;
- if(st[i].l==st[i].r)
- return;
- int mid=(st[i].l+st[i].r)>>1;
- build(i<<1,l,mid);
- build((i<<1)|1,mid+1,r);
- }
- void update(int i,int l,int r,int val)
- {
- if(val!=0)
- {
- if(st[i].l==l&&st[i].r==r)
- {
- st[i].lazy+=val;
- st[i].sum+=ll(r-l+1)*val;
- return;
- }
- }
- else
- {
- if(st[i].l==l&&st[i].r==r)
- {
- st[i].sum=0;
- st[i].lazy0=1;
- st[i].lazy=0;//保证当前节点的维护的值正确,别忘了这一句
- return;
- }
- pushDown(i,st[i].r-st[i].l+1);
- int mid=(st[i].l+st[i].r)>>1;
- if(r<=mid)
- update(i<<1,l,r,val);
- else if(l>mid)
- update((i<<1)|1,l,r,val);
- else
- {
- update(i<<1,l,mid,val);
- update((i<<1)|1,mid+1,r,val);
- }
- pushUp(i);
- }
- }
- ll query(int i,int l,int r)
- {
- if(st[i].l==l&&st[i].r==r)
- {
- return st[i].sum;
- }
- int mid=(st[i].l+st[i].r)>>1;
- pushDown(i,st[i].r-st[i].l+1);
- if(r<=mid)
- return query(i<<1,l,r);
- else if(l>mid)
- return query((i<<1)|1,l,r);
- else
- return query(i<<1,l,mid)+query((i<<1)|1,mid+1,r);
- }
- int t[maxn];
- int n,q;
- ll ans;
- int main()
- {
- int cas;
- t[0]=0;
- scanf("%d",&cas);
- while(cas--)
- {
- ans=0;
- scanf("%d%d",&n,&q);
- build(1,1,n);
- for(int i=1;i<=q;i++)
- {
- int l,r;
- scanf("%d%d%d",&t[i],&l,&r);
- update(1,1,n,t[i]-t[i-1]);
- ans+=query(1,l,r);
- update(1,l,r,0);
- }
- //printf("%I64d\n",ans);
- cout<<ans<<endl;
- }
- return 0;
- }