【BZOJ2157】旅遊-樹鏈剖分
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
3
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
3
2
1
-1
5
3
Hint
【資料範圍】
一共有10 個數據,對於第i (1 <= i <= 10) 個數據, N = M = i * 2000。
思路
- 樹鏈剖分
碼農題,執行操作:單點修改,區間修改,區間極值,區間求和 - insert相當於單點修改,變權變點權,附到深度大的點上
- 空間開夠
程式碼
#include <iostream> #include <cstdio> #include <cstring> #define maxn 40005 #define inf 20000005 using namespace std; struct node{int next,to,w;}e[maxn]; struct keeppp{int x,y,w;}q[maxn]; struct fdfdfd{int l,r,minn,maxx,sum,flag;}a[maxn<<1]; int siz[maxn],top[maxn],fa[maxn],son[maxn],num[maxn],fnum[maxn],deep[maxn]; int n,m,cnt,head[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,int d) { fa[u]=pre; deep[u]=d; 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,d+1); siz[u]+=siz[v]; if(son[u]==-1||siz[son[u]]<siz[v]) 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); a[x].minn=min(a[x<<1].minn,a[x<<1|1].minn); a[x].sum=a[x<<1].sum+a[x<<1|1].sum; } void pushdown(int x) { if(!a[x].flag) return; swap(a[x<<1].maxx,a[x<<1].minn); a[x<<1].maxx*=-1; a[x<<1].minn*=-1; a[x<<1].sum*=-1; swap(a[x<<1|1].maxx,a[x<<1|1].minn); a[x<<1|1].maxx*=-1; a[x<<1|1].minn*=-1; a[x<<1|1].sum*=-1; a[x].flag^=1; a[x<<1].flag^=1; a[x<<1|1].flag^=1; } void build(int x,int left,int right) { a[x].l=left; a[x].r=right; a[x].maxx=-inf; a[x].minn=inf; 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].minn=a[x].sum=d; return;} pushdown(x); insert(x<<1,v,d); insert(x<<1|1,v,d); pushup(x); } void modify(int x,int left,int right) { if(a[x].r<left||a[x].l>right) return; if(left<=a[x].l&&right>=a[x].r) { a[x].flag^=1; swap(a[x].maxx,a[x].minn); a[x].maxx*=-1; a[x].minn*=-1; a[x].sum*=-1; return; } pushdown(x); modify(x<<1,left,right); modify(x<<1|1,left,right); pushup(x); } void change(int u,int v) { while(top[u]!=top[v]) { if(deep[top[u]]<deep[top[v]]) swap(u,v); modify(1,num[top[u]],num[u]); u=fa[top[u]]; } if(u==v) return; if(deep[u]>deep[v]) swap(u,v); modify(1,num[son[u]],num[v]); } fdfdfd query(int x,int left,int right) { if(a[x].r<left||a[x].l>right) return (fdfdfd){0,0,inf,-inf,0,0}; if(left<=a[x].l&&right>=a[x].r) return a[x]; pushdown(x); fdfdfd temp1=query(x<<1,left,right),temp2=query(x<<1|1,left,right),temp; temp.sum=temp1.sum+temp2.sum; temp.maxx=max(temp1.maxx,temp2.maxx); temp.minn=min(temp1.minn,temp2.minn); return temp; } int asksum(int u,int v) { int ans=0; while(top[u]!=top[v]) { if(deep[top[u]]<deep[top[v]]) swap(u,v); ans+=query(1,num[top[u]],num[u]).sum; u=fa[top[u]]; } if(u==v) return ans; if(deep[u]>deep[v]) swap(u,v); ans+=query(1,num[son[u]],num[v]).sum; return ans; } int askmax(int u,int v) { int ans=-inf; while(top[u]!=top[v]) { if(deep[top[u]]<deep[top[v]]) swap(u,v); ans=max(ans,query(1,num[top[u]],num[u]).maxx); u=fa[top[u]]; } if(u==v) return ans; if(deep[u]>deep[v]) swap(u,v); ans=max(ans,query(1,num[son[u]],num[v]).maxx); return ans; } int askmin(int u,int v) { int ans=inf; while(top[u]!=top[v]) { if(deep[top[u]]<deep[top[v]]) swap(u,v); ans=min(ans,query(1,num[top[u]],num[u]).minn); u=fa[top[u]]; } if(u==v) return ans; if(deep[u]>deep[v]) swap(u,v); ans=min(ans,query(1,num[son[u]],num[v]).minn); return ans; } 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); ++q[i].x; ++q[i].y; addedge(q[i].x,q[i].y,q[i].w),addedge(q[i].y,q[i].x,q[i].w); } dfs_1(1,0,1); 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); } scanf("%d",&m); while(m--) { char op[5]; int u,v; scanf("%s%d%d",&op,&u,&v); ++u,++v; if(op[0]=='C') insert(1,num[u],--v); else if(op[0]=='N') change(u,v); else if(op[0]=='S') printf("%d\n",asksum(u,v)); else if(op[0]=='M'&&op[1]=='A') printf("%d\n",askmax(u,v)); else printf("%d\n",askmin(u,v)); } return 0; }