题解:裸树剖啊 线段树打打标记维护就好了啊 我为什么要写LCT啊 感觉石乐志了 我常数怎么这么大啊 我好菜了啊
树剖版本:
/************************************************************** Problem: 2157 User: c20161007 Language: C++ Result: Accepted Time:716 ms Memory:21352 kb ****************************************************************/ #include <bits/stdc++.h> const int MAXN=2e5+10; const int inf=1e9+7; using namespace std; int n; int fa[MAXN],dep[MAXN],num[MAXN],son[MAXN]; int key[MAXN]; int pos[MAXN]; vector<pair<int,pair<int,int> > >vec[MAXN]; void dfs1(int v,int pre,int deep){ fa[v]=pre;dep[v]=deep+1;num[v]=1; for(int i=0;i<vec[v].size();i++){ int u=vec[v][i].first; if(u!=pre){ key[u]=vec[v][i].second.first; pos[vec[v][i].second.second]=u; dfs1(u,v,deep+1); num[v]+=num[u]; if(son[v]==-1||num[son[v]]<num[u])son[v]=u; } } } int p[MAXN],fp[MAXN],tp[MAXN]; int cnt; void dfs2(int v,int td){ p[v]=++cnt;fp[p[v]]=v;tp[v]=td; if(son[v]!=-1)dfs2(son[v],td); for(int i=0;i<vec[v].size();i++){ int u=vec[v][i].first; if(u!=fa[v]&&u!=son[v])dfs2(u,u); } } int sum[MAXN<<2],minn[MAXN<<2],maxx[MAXN<<2]; bool flag[MAXN<<2]; void up(int x){ sum[x]=sum[x<<1]+sum[x<<1|1]; minn[x]=min(minn[x<<1],minn[x<<1|1]); maxx[x]=max(maxx[x<<1],maxx[x<<1|1]); } void push(int x){ if(flag[x]){ flag[x<<1]^=1;flag[x<<1|1]^=1; sum[x<<1]*=-1;swap(minn[x<<1],maxx[x<<1]);minn[x<<1]*=-1;maxx[x<<1]*=-1; sum[x<<1|1]*=-1;swap(minn[x<<1|1],maxx[x<<1|1]);minn[x<<1|1]*=-1;maxx[x<<1|1]*=-1; flag[x]=0; } } void built(int rt,int l,int r){ if(l==r){sum[rt]=minn[rt]=maxx[rt]=key[fp[l]];return ;} int mid=(l+r)>>1; built(rt<<1,l,mid); built(rt<<1|1,mid+1,r); up(rt); } void update(int rt,int l,int r,int t,int vul){ if(l==r){sum[rt]=minn[rt]=maxx[rt]=vul;return ;} int mid=(l+r)>>1; push(rt); if(t<=mid)update(rt<<1,l,mid,t,vul); else update(rt<<1|1,mid+1,r,t,vul); up(rt); } void update1(int rt,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ flag[rt]^=1; sum[rt]*=-1;swap(minn[rt],maxx[rt]); minn[rt]*=-1;maxx[rt]*=-1; return ; } int mid=(l+r)>>1; push(rt); if(ql<=mid)update1(rt<<1,l,mid,ql,qr); if(qr>mid)update1(rt<<1|1,mid+1,r,ql,qr); up(rt); } pair<int,pair<int,int> >ans1; void querty(int rt,int l,int r,int ql,int qr){ if(ql<=l&&r<=qr){ans1.first+=sum[rt],ans1.second.first=min(ans1.second.first,minn[rt]),ans1.second.second=max(ans1.second.second,maxx[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); } void slove1(int u,int v){ int uu=tp[u];int vv=tp[v]; while(uu!=vv){ if(dep[uu]<dep[vv])swap(u,v),swap(uu,vv); update1(1,1,n,p[uu],p[u]); u=fa[uu];uu=tp[u]; } if(dep[u]>dep[v])swap(u,v); if(u!=v)update1(1,1,n,p[son[u]],p[v]); } int slove(int u,int v,int op){ //cout<<u<<" "<<v<<endl; int uu=tp[u];int vv=tp[v]; // cout<<uu<<" "<<vv<<endl; ans1.first=0;ans1.second.first=inf;ans1.second.second=-1*inf; while(uu!=vv){ if(dep[uu]<dep[vv])swap(u,v),swap(uu,vv); querty(1,1,n,p[uu],p[u]); u=fa[uu];uu=tp[u]; // cout<<vv<<" "<<uu<<endl; } // cout<<ans1.first<<endl; if(dep[u]>dep[v])swap(u,v); if(u!=v)querty(1,1,n,p[son[u]],p[v]); if(op==1)return ans1.first; if(op==2)return ans1.second.first; return ans1.second.second; } int main(){ scanf("%d",&n);int u,v,vul; for(int i=1;i<=n;i++)son[i]=-1; for(int i=1;i<n;i++){ scanf("%d%d%d",&u,&v,&vul);u++;v++; vec[u].push_back(make_pair(v,make_pair(vul,i))); vec[v].push_back(make_pair(u,make_pair(vul,i))); } dfs1(1,0,0);dfs2(1,1); // for(int i=1;i<=n;i++)cout<<p[i]<<" "; // cout<<endl; built(1,1,n); int m;scanf("%d",&m);char str[5]; for(int i=1;i<=m;i++){ scanf("%s",str); scanf("%d%d",&u,&v); if(str[0]!='C')u++,v++; if(str[0]=='C')update(1,1,n,p[pos[u]],v); else if(str[0]=='N')slove1(u,v); else if(str[0]=='S')printf("%d ",slove(u,v,1)); else if(str[1]=='I')printf("%d ",slove(u,v,2)); else printf("%d ",slove(u,v,3)); } return 0; }
LCT版本:
/************************************************************** Problem: 2157 User: c20161007 Language: C++ Result: Accepted Time:544 ms Memory:4832 kb ****************************************************************/ #include <bits/stdc++.h> const int MAXN=2e4+10; const int inf=1e9+7; #define mp make_pair #define pb push_back using namespace std; int ch[MAXN][2],res[MAXN],size[MAXN],flag[MAXN],maxx[MAXN],minn[MAXN],sum[MAXN],pre[MAXN],key[MAXN]; int flag1[MAXN],f[MAXN][21],dep[MAXN]; bool rt[MAXN]; int st[MAXN],tp; typedef struct node{ int v,vul,id; }node; vector<node>vec[MAXN]; int vis[MAXN]; int cnt; void Treavel(int x) { if(x) { Treavel(ch[x][0]); printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size=%2d key=%2d ",x,ch[x][0],ch[x][1],pre[x],size[x],key[x]); Treavel(ch[x][1]); } } void debug(int rp) { printf("root:%d ",rp); Treavel(rp); } inline void newnode(int x,int vul,int fa){ ch[x][0]=ch[x][1]=0; flag1[x]=res[x]=flag[x]=0;size[x]=1;maxx[x]=minn[x]=key[x]=sum[x]=vul; pre[x]=fa;rt[x]=1; return ; } inline void reverse(int r){ if(!r)return ; swap(ch[r][0],ch[r][1]); res[r]^=1; } inline void Add(int r,int vul){ if(!r)return ; key[r]+=vul;maxx[r]+=vul;minn[r]+=vul;sum[r]+=size[r]*vul; flag[r]+=vul; } inline void Fan(int r){ if(!r)return ; key[r]*=-1;sum[r]*=-1;swap(maxx[r],minn[r]);maxx[r]*=-1;minn[r]*=-1; flag1[r]^=1; } inline void push(int x){ if(res[x]){ reverse(ch[x][0]); reverse(ch[x][1]); res[x]^=1; } if(flag[x]){ Add(ch[x][0],flag[x]); Add(ch[x][1],flag[x]); flag[x]=0; } if(flag1[x]){ Fan(ch[x][0]); Fan(ch[x][1]); flag1[x]^=1; } } inline void up(int x){ sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+key[x]; minn[x]=key[x];maxx[x]=key[x]; if(minn[x]>minn[ch[x][0]])minn[x]=minn[ch[x][0]]; if(minn[x]>minn[ch[x][1]])minn[x]=minn[ch[x][1]]; if(maxx[x]<maxx[ch[x][0]])maxx[x]=maxx[ch[x][0]]; if(maxx[x]<maxx[ch[x][1]])maxx[x]=maxx[ch[x][1]]; size[x]=size[ch[x][0]]+size[ch[x][1]]+1; } inline bool pd1(int x){ return ch[pre[x]][0]!=x&&ch[pre[x]][1]!=x; } inline void P(int x){ int i;st[++tp]=x; for(i=x;!pd1(i);i=pre[i]) st[++tp]=pre[i]; for(;tp;tp--) push(st[tp]); } inline void rotate(int x,int kind){ int y=pre[x]; pre[ch[x][kind]]=y;ch[y][!kind]=ch[x][kind]; if(!rt[y])ch[pre[y]][ch[pre[y]][1]==y]=x; else rt[y]=0,rt[x]=1; pre[x]=pre[y];ch[x][kind]=y;pre[y]=x; up(y);up(x); } inline void splay(int x){ P(x); while(!rt[x]){ if(rt[pre[x]])rotate(x,ch[pre[x]][0]==x); else{ int y=pre[x];int kind=ch[pre[y]][0]==y; if(ch[y][kind]==x)rotate(x,!kind),rotate(x,kind); else rotate(y,kind),rotate(x,kind); } } up(x); } inline void access(int x){ int y=0; while(x){ splay(x); if(ch[x][1])rt[ch[x][1]]=1,pre[ch[x][1]]=x,ch[x][1]=0; if(y)rt[y]=0; ch[x][1]=y;up(x); y=x;x=pre[x]; } } inline void mroot(int x){ access(x);splay(x);reverse(x); } void dfs(int v,int ff,int deep){ f[v][0]=ff;dep[v]=deep+1; for(int i=0;i<vec[v].size();i++){ if(vec[v][i].v!=ff){ newnode(vec[v][i].v,vec[v][i].vul,v); vis[vec[v][i].id]=vec[v][i].v; dfs(vec[v][i].v,v,deep+1); } } } void dfs1(int v){ for(int i=1;i<=20;i++)f[v][i]=f[f[v][i-1]][i-1]; for(int i=0;i<vec[v].size();i++)if(vec[v][i].v!=f[v][0])dfs1(vec[v][i].v); } int Lca(int u,int v){ if(dep[u]<dep[v])swap(u,v); int tmp=dep[u]-dep[v]; for(int i=0;i<=20;i++)if((tmp&(1<<i)))u=f[u][i]; if(u==v)return u; for(int i=20;i>=0;i--){ if(f[u][i]!=f[v][i]){ u=f[u][i];v=f[v][i]; } } return f[u][0]; } inline void update(int v,int vul){ splay(v);key[v]=vul;up(v); } inline void update1(int u,int v){ int lca=Lca(u,v); if(v!=lca){mroot(lca);access(v);splay(lca);Fan(ch[lca][1]);} if(u!=lca){mroot(lca);access(u);splay(lca);Fan(ch[lca][1]);} return ; } inline int querty(int u,int v){ int lca=Lca(u,v);int t1=0; if(v!=lca){mroot(lca);access(v);splay(lca);t1+=sum[ch[lca][1]];} if(u!=lca){mroot(lca);access(u);splay(lca);t1+=sum[ch[lca][1]];} return t1; } inline int Max(int u,int v){ int lca=Lca(u,v);int t1=-1*inf; //cout<<u<<" "v<<endl; if(v!=lca){mroot(lca);access(v);splay(lca);t1=max(t1,maxx[ch[lca][1]]);} if(u!=lca){mroot(lca);access(u);splay(lca);t1=max(t1,maxx[ch[lca][1]]);} return t1; } inline int Min(int u,int v){ int lca=Lca(u,v);int t1=inf; if(v!=lca){mroot(lca);access(v);splay(lca);t1=min(t1,minn[ch[lca][1]]);} if(u!=lca){mroot(lca);access(u);splay(lca);t1=min(t1,minn[ch[lca][1]]);} return t1; } int main(){ int n;scanf("%d",&n);int u,v,vul; sum[0]=0;maxx[0]=-inf;minn[0]=inf; for(int i=1;i<n;i++)scanf("%d%d%d",&u,&v,&vul),u++,v++,vec[u].pb((node){v,vul,i}),vec[v].pb((node){u,vul,i}); dfs(1,0,0);dfs1(1);newnode(1,0,0); //cout<<pre[3]<<endl; int m;scanf("%d",&m);char str[15]; for(int i=1;i<=m;i++){ scanf("%s%d%d",str,&u,&v); if(str[0]=='C')update(vis[u],v); else if(str[0]=='N')u++,v++,update1(u,v); else if(str[0]=='S')u++,v++,printf("%d ",querty(u,v)); else if(str[1]=='I')u++,v++,printf("%d ",Min(u,v)); else if(str[1]=='A')u++,v++,printf("%d ",Max(u,v)); } return 0; }
2157: 旅游
Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 2471 Solved: 1017
[Submit][Status][Discuss]
Description
Ray 乐忠于旅游,这次他来到了T 城。T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥连接。为了方便游客到达每个景点但又为了节约成本,T 城的任意两个景点之间有且只有一条路径。换句话说, T 城中只有N − 1 座桥。Ray 发现,有些桥上可以看到美丽的景色,让人心情愉悦,但有些桥狭窄泥泞,令人烦躁。于是,他给每座桥定义一个愉悦度w,也就是说,Ray 经过这座桥会增加w 的愉悦度,这或许是正的也可能是负的。有时,Ray 看待同一座桥的心情也会发生改变。现在,Ray 想让你帮他计算从u 景点到v 景点能获得的总愉悦度。有时,他还想知道某段路上最美丽的桥所提供的最大愉悦度,或是某段路上最糟糕的一座桥提供的最低愉悦度。
Input
输入的第一行包含一个整数N,表示T 城中的景点个数。景点编号为 0...N − 1。接下来N − 1 行,每行三个整数u、v 和w,表示有一条u 到v,使 Ray 愉悦度增加w 的桥。桥的编号为1...N − 1。|w| <= 1000。输入的第N + 1 行包含一个整数M,表示Ray 的操作数目。接下来有M 行,每行描述了一个操作,操作有如下五种形式: C i w,表示Ray 对于经过第i 座桥的愉悦度变成了w。 N u v,表示Ray 对于经过景点u 到v 的路径上的每一座桥的愉悦度都变成原来的相反数。 SUM u v,表示询问从景点u 到v 所获得的总愉悦度。 MAX u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最大愉悦度。 MIN u v,表示询问从景点u 到v 的路径上的所有桥中某一座桥所提供的最小愉悦度。测试数据保证,任意时刻,Ray 对于经过每一座桥的愉悦度的绝对值小于等于1000。
Output
对于每一个询问(操作S、MAX 和MIN),输出答案。
Sample Input
0 1 1
1 2 2
8
SUM 0 2
MAX 0 2
N 0 1
SUM 0 2
MIN 0 2
C 1 3
SUM 0 2
MAX 0 2
Sample Output
2
1
-1
5
3
HINT
一共有10 个数据,对于第i (1 <= i <= 10) 个数据, N = M = i * 2000。