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;
}