Description
毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。爬啊爬爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果 “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:
Change k w:将第k条树枝上毛毛果的个数改变为w个。
Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。
由于毛毛虫很贪,于是他会有如下询问:
Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。
Input
第一行一个正整数N。 接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。 接下来是操作和询问,以“Stop”结束。
Output
对于毛毛虫的每个询问操作,输出一个答案。
Sample Input
4 1 2 8 1 3 7 3 4 9 Max 2 4 Cover 2 4 5 Add 1 4 10 Change 1 16 Max 2 4 Stop
Sample Output
9 16
Hint
1<=N<=100,000,操作+询问数目不超过100,000。 保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个。
思路
- 树剖题,要注意标记,先执行cover标记,若无覆盖再执行add
- 赋值-1的原因:果子个数为正
- 改大半天后发现错误原因是
x<<1
写成了x<1
吐血三升 - 文末再附一个洛谷剽来的数据生成器 方便调试
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#define maxn 100005
using namespace std;
struct fdfdfd{int l,r,maxx,a,c;}a[maxn<<2];
struct node{int next,to,w;}e[maxn];
struct keeppp{int x,y,w;}q[maxn];
int n,cnt,head[maxn];
int deep[maxn],fa[maxn],son[maxn],siz[maxn],top[maxn],num[maxn],fnum[maxn];
void addedge(int x,int y,int w){e[++cnt].to=y; e[cnt].w=w; e[cnt].next=head[x]; head[x]=cnt;}
void dfs_1(int u,int pre)
{
deep[u]=deep[pre]+1; fa[u]=pre; siz[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v!=pre)
{
dfs_1(v,u); siz[u]+=siz[v];
if(son[u]==-1||siz[v]>siz[son[u]]) son[u]=v;
}
}
}
void dfs_2(int u,int topp)
{
top[u]=topp; num[u]=++cnt; fnum[cnt]=u;
if(son[u]!=-1) dfs_2(son[u],topp);
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(v!=fa[u]&&v!=son[u]) dfs_2(v,v);
}
}
void pushup(int x) {a[x].maxx=max(a[x<<1].maxx,a[x<<1|1].maxx);}
void pushdown(int x)
{
if(a[x].c!=-1)
{
a[x<<1].c=a[x<<1|1].c=a[x].c;
a[x<<1].maxx=a[x<<1|1].maxx=a[x].c;
a[x<<1].a=a[x<<1|1].a=0;
a[x].c=-1;
}
if(a[x].a!=0)
{
a[x<<1].maxx+=a[x].a; a[x<<1|1].maxx+=a[x].a;
a[x<<1].a+=a[x].a; a[x<<1|1].a+=a[x].a;
a[x].a=0;
}
}
void build(int x,int left,int right)
{
a[x].l=left; a[x].r=right; a[x].c=-1;
if(left==right) return;
int mid=(left+right)>>1;
build(x<<1,left,mid); build(x<<1|1,mid+1,right);
}
void insert(int x,int v,int d)
{
if(a[x].r<v||a[x].l>v) return;
if(a[x].r==v&&a[x].l==v) {a[x].maxx=a[x].c=d; a[x].a=0; return;}
pushdown(x);
insert(x<<1,v,d); insert(x<<1|1,v,d);
pushup(x);
}
void change_add(int x,int left,int right,int d)
{
if(a[x].r<left||a[x].l>right) return;
if(left<=a[x].l&&right>=a[x].r)
{
a[x].maxx+=d; a[x].a+=d;
return;
}
pushdown(x);
change_add(x<<1,left,right,d); change_add(x<<1|1,left,right,d);
pushup(x);
}
void change_cover(int x,int left,int right,int d)
{
if(a[x].r<left||a[x].l>right) return;
if(left<=a[x].l&&right>=a[x].r)
{
a[x].maxx=d; a[x].c=d; a[x].a=0;
return;
}
pushdown(x);
change_cover(x<<1,left,right,d); change_cover(x<<1|1,left,right,d);
pushup(x);
}
void modify_add(int u,int v,int d)
{
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]]) swap(u,v);
change_add(1,num[top[u]],num[u],d);
u=fa[top[u]];
}
if(u==v) return;
if(deep[u]>deep[v]) swap(u,v);
change_add(1,num[son[u]],num[v],d);
}
void modify_cover(int u,int v,int d)
{
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]]) swap(u,v);
change_cover(1,num[top[u]],num[u],d);
u=fa[top[u]];
}
if(u==v) return;
if(deep[u]>deep[v]) swap(u,v);
change_cover(1,num[son[u]],num[v],d);
}
int query(int x,int left,int right)
{
if(a[x].r<left||a[x].l>right) return -1;
if(left<=a[x].l&&right>=a[x].r) return a[x].maxx;
pushdown(x);
return max(query(x<<1,left,right),query(x<<1|1,left,right));
}
int askmax(int u,int v)
{
int maxx=0;
while(top[u]!=top[v])
{
if(deep[top[u]]<deep[top[v]]) swap(u,v);
maxx=max(maxx,query(1,num[top[u]],num[u]));
u=fa[top[u]];
}
if(u==v) return maxx;
if(deep[u]>deep[v]) swap(u,v);
maxx=max(maxx,query(1,num[son[u]],num[v]));
return maxx;
}
int main()
{
memset(son,-1,sizeof(son));
scanf("%d",&n);
for(int i=1;i<n;++i)
scanf("%d%d%d",&q[i].x,&q[i].y,&q[i].w),addedge(q[i].x,q[i].y,q[i].w),addedge(q[i].y,q[i].x,q[i].w);
dfs_1(1,0); cnt=0; dfs_2(1,1); build(1,1,n);
for(int i=1;i<n;++i)
{
if(deep[q[i].x]<deep[q[i].y]) swap(q[i].x,q[i].y);
insert(1,num[q[i].x],q[i].w);
}
char op[8]; int u,v,w;
while(scanf("%s",&op))
{
if(op[0]=='S') break;
if(op[0]=='C'&&op[1]=='h') scanf("%d%d",&u,&w),insert(1,num[q[u].x],w);
else if(op[0]=='C'&&op[1]=='o') scanf("%d%d%d",&u,&v,&w),modify_cover(u,v,w);
else if(op[0]=='A') scanf("%d%d%d",&u,&v,&w),modify_add(u,v,w);
else scanf("%d%d",&u,&v),printf("%d
",askmax(u,v));
}
/* Change k w:将第k条树枝上毛毛果的个数改变为w个。
Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。
Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。*/
return 0;
}
附:(数据生成器)
#include <bits/stdc++.h>
using namespace std;
int fa[100005],f[100005];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int main()
{
srand(time(0));
int T=1;
// cout<<T<<endl;
while(T--)
{
memset(f,0,sizeof(f));
int n=10;
for(int i=1;i<=n;i++)fa[i]=i;
int root=rand()%n+1;
cout<<n<<endl;
for(int i=1;i<=n;i++)
{
if(i==root)continue;
int father;
do{father=rand()%n+1;}while(find(i)==find(father));
f[i]=father;
fa[find(i)]=find(father);
}
for(int i=1;i<=n;i++)
{
if(root==i)continue;
cout<<i<<" "<<f[i]<<" "<<rand()%10<<endl;
}
int m=20;
while(m--)
{
int opt=rand()%4;
string s;
switch(opt)
{
case 0:s="Change";break;
case 1:s="Cover";break;
case 2:s="Add";break;
case 3:s="Max";break;
}
cout<<s<<" ";
if(opt==0) cout<<rand()%(n-1)+1<<" "<<rand()%100<<endl;
else if(opt==1) cout<<rand()%n+1<<" "<<rand()%n+1<<" "<<rand()%100<<endl;
else if(opt==2) cout<<rand()%n+1<<" "<<rand()%n+1<<" "<<rand()%100<<endl;
else cout<<rand()%n+1<<" "<<rand()%n+1<<endl;
}
cout<<"Stop"<<endl;
}
}