BZOJ2157: 旅游
【传送门:BZOJ3676】
简要题意:
给出一棵树,树上的边有权值(可正可负),对这棵树有5种操作:
1.SUM x y求出x点到y点所经过的边权和
2.MAX x y求出x点到y点所经过的边的最大边权
3.MIN x y求出x点到y点所经过的边的最小边权
4.C x y将输入的第x条边的边权改为y
5.N x y将x点到y点所经过的边的边权全部变成自己的相反数
题解:
很显然,在树上求路径特征值,用树链剖分
对于边权,就把边权变为这条边深度最深的点的点权,然后在求特征值的时候注意一下就行了
关键是相反数问题,注意:假设一段区间的和为s,最大值为mx,最小值为mn,那么取相反数后,这段区间的和为-s,最大值为-mn,最小值为-mx
然后因为修改的是区间,所以要用lazy标记来继承状态
因为原题的点编号为0到n-1,有点恶心,所以把编号改为1到n
然而我,就因为在一个操作中没有x++,y++,卡了一个中午
参考代码:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<algorithm> using namespace std; struct node { int x,y,next; }a[41000];int len,last[21000]; struct trnode { int l,r,lc,rc,mn,mx,s; int lazy; trnode() { lazy=0; } }tr[41000];int trlen; void ins(int x,int y) { len++; a[len].x=x;a[len].y=y; a[len].next=last[x];last[x]=len; } void update(int x) { int lc=tr[x].lc,rc=tr[x].rc; int mn,mx; if(lc!=-1) { mn=tr[lc].mn;mx=tr[lc].mx; tr[lc].mn=-mx;tr[lc].mx=-mn; tr[lc].s=-tr[lc].s; tr[lc].lazy^=1; } if(rc!=-1) { mn=tr[rc].mn;mx=tr[rc].mx; tr[rc].mn=-mx;tr[rc].mx=-mn; tr[rc].s=-tr[rc].s; tr[rc].lazy^=1; } tr[x].lazy=0; } void follow(int x) { int lc=tr[x].lc,rc=tr[x].rc; tr[x].s=tr[lc].s+tr[rc].s; tr[x].mx=max(tr[lc].mx,tr[rc].mx); tr[x].mn=min(tr[lc].mn,tr[rc].mn); } void bt(int l,int r) { trlen++;int now=trlen; tr[now].l=l;tr[now].r=r;tr[now].lc=tr[now].rc=-1; tr[now].mn=tr[now].mx=0;tr[now].s=0; if(l<r) { int mid=(l+r)/2; tr[now].lc=trlen+1;bt(l,mid); tr[now].rc=trlen+1;bt(mid+1,r); } } int tot[21000],fa[21000],dep[21000],son[21000]; void pre_tree_node(int x) { tot[x]=1;son[x]=0; for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa[x]) { dep[y]=dep[x]+1; fa[y]=x; pre_tree_node(y); tot[x]+=tot[y]; if(tot[y]>tot[son[x]]) son[x]=y; } } } int ys[21000],z,top[21000]; void pre_tree_edge(int x,int tp) { ys[x]=++z;top[x]=tp; if(son[x]!=0) pre_tree_edge(son[x],tp); for(int k=last[x];k;k=a[k].next) { int y=a[k].y; if(y!=fa[x]&&y!=son[x]) pre_tree_edge(y,y); } } void add(int now,int x,int c) { if(tr[now].l==tr[now].r) { tr[now].s=c; tr[now].mx=tr[now].mn=tr[now].s; return ; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy==1) update(now); if(x<=mid) add(lc,x,c); else add(rc,x,c); follow(now); } void xf(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r) { tr[now].lazy^=1; int mn=tr[now].mn,mx=tr[now].mx; tr[now].mx=-mn;tr[now].mn=-mx; tr[now].s=-tr[now].s; return ; } int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy==1) update(now); if(r<=mid) xf(lc,l,r); else if(l>mid) xf(rc,l,r); else { xf(lc,l,mid);xf(rc,mid+1,r); } follow(now); } void change(int x,int y) { int tx=top[x],ty=top[y]; while(tx!=ty) { if(dep[tx]>dep[ty]) { swap(tx,ty); swap(x,y); } xf(1,ys[ty],ys[y]); y=fa[ty];ty=top[y]; } if(x!=y) { if(dep[x]>dep[y]) swap(x,y); xf(1,ys[son[x]],ys[y]); } } int getsum(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r) return tr[now].s; int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy==1) update(now); if(r<=mid) return getsum(lc,l,r); else if(l>mid) return getsum(rc,l,r); else return getsum(lc,l,mid)+getsum(rc,mid+1,r); } int findmax(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r) return tr[now].mx; int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy==1) update(now); if(r<=mid) return findmax(lc,l,r); else if(l>mid) return findmax(rc,l,r); else return max(findmax(lc,l,mid),findmax(rc,mid+1,r)); } int findmin(int now,int l,int r) { if(tr[now].l==l&&tr[now].r==r) return tr[now].mn; int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2; if(tr[now].lazy==1) update(now); if(r<=mid) return findmin(lc,l,r); else if(l>mid) return findmin(rc,l,r); else return min(findmin(lc,l,mid),findmin(rc,mid+1,r)); } int solve(int x,int y,int t) { if(t==1) { int ans=0,tx=top[x],ty=top[y]; while(tx!=ty) { if(dep[tx]>dep[ty]) { swap(tx,ty); swap(x,y); } ans+=getsum(1,ys[ty],ys[y]); y=fa[ty];ty=top[y]; } if(x==y) return ans; else { if(dep[x]>dep[y]) swap(x,y); return ans+getsum(1,ys[son[x]],ys[y]); } } else if(t==2) { int ans=-999999999,tx=top[x],ty=top[y]; while(tx!=ty) { if(dep[tx]>dep[ty]) { swap(tx,ty); swap(x,y); } ans=max(ans,findmax(1,ys[ty],ys[y])); y=fa[ty];ty=top[y]; } if(x==y) return ans; else { if(dep[x]>dep[y]) swap(x,y); return max(ans,findmax(1,ys[son[x]],ys[y])); } } else if(t==3) { int ans=999999999,tx=top[x],ty=top[y]; while(tx!=ty) { if(dep[tx]>dep[ty]) { swap(tx,ty); swap(x,y); } ans=min(ans,findmin(1,ys[ty],ys[y])); y=fa[ty];ty=top[y]; } if(x==y) return ans; else { if(dep[x]>dep[y]) swap(x,y); return min(ans,findmin(1,ys[son[x]],ys[y])); } } } struct enode { int x,y,d; }e[21000]; int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int n; scanf("%d",&n); len=0;memset(last,0,sizeof(last)); for(int i=1;i<n;i++) { scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].d); e[i].x++;e[i].y++; ins(e[i].x,e[i].y);ins(e[i].y,e[i].x); } dep[1]=0;fa[1]=0;pre_tree_node(1); z=0;pre_tree_edge(1,1); trlen=0;bt(1,z); for(int i=1;i<n;i++) if(dep[e[i].x]>dep[e[i].y]) swap(e[i].x,e[i].y); for(int i=1;i<n;i++) add(1,ys[e[i].y],e[i].d); int m; scanf("%d",&m); char st[5]; for(int i=1;i<=m;i++) { scanf("%s",st+1); int x,y; scanf("%d%d",&x,&y); if(st[1]=='C') { add(1,ys[e[x].y],y); continue; } x++;y++; if(st[1]=='N') change(x,y); if(st[1]=='S') printf("%d\n",solve(x,y,1)); if(st[1]=='M'&&st[2]=='A') printf("%d\n",solve(x,y,2)); if(st[1]=='M'&&st[2]=='I') printf("%d\n",solve(x,y,3)); } return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚