BZOJ1984: 月下“毛景树”
题解:裸树剖+线段树
/************************************************************** Problem: 1984 User: c20161007 Language: C++ Result: Accepted Time:4852 ms Memory:15324 kb ****************************************************************/ #include <bits/stdc++.h> #define f first #define s second #define ll long long const int MAXN=1e5+10; using namespace std; int fa[MAXN],dep[MAXN],num[MAXN],son[MAXN],vis[MAXN],a[MAXN]; vector<pair<int,pair<int,int> > >vec[MAXN]; int n;char str[101]; ll read(){ ll x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } void dfs(int v,int pre,int deep){ fa[v]=pre;num[v]=1;dep[v]=deep+1; for(int i=0;i<vec[v].size();i++){ int u=vec[v][i].f; if(u!=pre){ a[u]=vec[v][i].s.f;vis[vec[v][i].s.s]=u; dfs(u,v,deep+1); num[v]+=num[u]; if(son[v]==-1||num[son[v]]<num[u])son[v]=u; } } } int p[MAXN],tp[MAXN],fp[MAXN],cnt; void dfs1(int v,int td){ p[v]=++cnt;fp[p[v]]=v;tp[v]=td; if(son[v]!=-1)dfs1(son[v],td); for(int i=0;i<vec[v].size();i++){ if(vec[v][i].f!=son[v]&&vec[v][i].f!=fa[v])dfs1(vec[v][i].f,vec[v][i].f); } } int key[MAXN<<2],flag[MAXN<<2],flag1[MAXN<<2]; void push(int x){ if(flag[x]>=0){ flag1[x<<1]=flag1[x<<1|1]=0;flag[x<<1]=flag[x<<1|1]=flag[x]; key[x<<1]=key[x<<1|1]=flag[x]; flag[x]=-1; } if(flag1[x]){ flag1[x<<1]+=flag1[x];flag1[x<<1|1]+=flag1[x]; key[x<<1]+=flag1[x];key[x<<1|1]+=flag1[x]; flag1[x]=0; } } void up(int x){key[x]=max(key[x<<1],key[x<<1|1]);return ;} void built(int rt,int l,int r){ flag[rt]=-1;flag1[rt]=0; if(l==r){key[rt]=a[fp[l]];return ;} int mid=(l+r)>>1; built(rt<<1,l,mid); built(rt<<1|1,mid+1,r); up(rt); } void update1(int rt,int l,int r,int t,int vul){ if(l==r){key[rt]=vul;return ;} int mid=(l+r)>>1; push(rt); if(t<=mid)update1(rt<<1,l,mid,t,vul); else update1(rt<<1|1,mid+1,r,t,vul); up(rt); } void update2(int rt,int l,int r,int ql,int qr,int t){ if(ql<=l&&r<=qr){key[rt]=t;flag1[rt]=0;flag[rt]=t;return ;} int mid=(l+r)>>1; push(rt); if(ql<=mid)update2(rt<<1,l,mid,ql,qr,t); if(qr>mid)update2(rt<<1|1,mid+1,r,ql,qr,t); up(rt); } void update3(int rt,int l,int r,int ql,int qr,int t){ if(ql<=l&&r<=qr){key[rt]+=t;flag1[rt]+=t;return ;} int mid=(l+r)>>1; push(rt); if(ql<=mid)update3(rt<<1,l,mid,ql,qr,t); if(qr>mid)update3(rt<<1|1,mid+1,r,ql,qr,t); up(rt); } int ans; void querty(int rt,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ans=max(ans,key[rt]);return ;} int mid=(l+r)>>1; push(rt); if(ql<=mid)querty(rt<<1,l,mid,ql,qr); if(qr>mid)querty(rt<<1|1,mid+1,r,ql,qr); up(rt); } int slove(int u,int v,int op,int w){ int uu=tp[u];int vv=tp[v];int ans1=-1; while(uu!=vv){ if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v); if(op==1)update2(1,1,n,p[uu],p[u],w); else if(op==2)update3(1,1,n,p[uu],p[u],w); else ans=-1,querty(1,1,n,p[uu],p[u]),ans1=max(ans1,ans); u=fa[uu];uu=tp[u]; } if(dep[u]>dep[v])swap(u,v); if(u!=v){ if(op==1)update2(1,1,n,p[son[u]],p[v],w); else if(op==2)update3(1,1,n,p[son[u]],p[v],w); else ans=-1,querty(1,1,n,p[son[u]],p[v]),ans1=max(ans1,ans); } return ans1; } int main(){ n=read();int u,v,vul; for(int i=1;i<n;i++)u=read(),v=read(),vul=read(),vec[u].push_back(make_pair(v,make_pair(vul,i))),vec[v].push_back(make_pair(u,make_pair(vul,i))); for(int i=1;i<=n;i++)son[i]=-1; dfs(1,0,0);dfs1(1,1);built(1,1,n); //for(int i=1;i<=n;i++)cout<<num[i]<<" "; //cout<<endl; //cout<<"sb"<<endl; while(1){ scanf(" %s",str); if(str[0]=='S')break; if(str[1]=='h'){ u=read();v=read();update1(1,1,n,p[vis[u]],v); } else if(str[1]=='o'){ u=read();v=read();vul=read();slove(u,v,1,vul); } else if(str[0]=='A'){ u=read(),v=read(),vul=read(),slove(u,v,2,vul); } else{ u=read();v=read(); printf("%d\n",slove(u,v,3,0)); } } return 0; }
1984: 月下“毛景树”
Time Limit: 20 Sec Memory Limit: 64 MBSubmit: 2438 Solved: 713
[Submit][Status][Discuss]
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
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
【Data Range】
1<=N<=100,000,操作+询问数目不超过100,000。
保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个。
16
【Data Range】
1<=N<=100,000,操作+询问数目不超过100,000。
保证在任意时刻,所有树枝上毛毛果的个数都不会超过10^9个。