題意就是給你一棵樹,每條邊上都有權值,有三種操作,把某條邊的權值變成v,把點a到點b之間的路徑上的邊的權值都乘上-1,求a到b的路徑上的最大值。
其實這題的線段樹要比樹鏈剖分難寫,首先,因為有乘-1的操作,所以不光要維護最大值,還要維護最小值,這樣在乘-1後,最大值就可以直接根據最小值得到,當然,延遲操作是必須的,其中細節還是蠻多的,需要注意。
好久沒敲線段樹了,wa了好多發,話說這線段樹是有點難度啊,還是自己太弱了。。。
好久沒寫200+的**了。。。。
#include#include#includeusing namespace std;
const int maxn = 50010;
int sum1[maxn*4],sum2[maxn*4],add[maxn*4];
struct siside[maxn*2];
int head[maxn];
int tid[maxn],ran[maxn],num[maxn],son[maxn];
int top[maxn],fa[maxn],siz[maxn],dep[maxn];
int tim,cnt;
int n;
void dfs1(int u,int father,int d)
}}void dfs2(int u,int tp)
pushdown(l,r,rt);
int mid=(l+r)/2;
if(mid>=l) update(l,r,c,l,mid,rt<<1);
if(mid+1<=r) update(l,r,c,mid+1,r,rt<<1|1);
sum1[rt]=max(sum1[rt<<1],sum1[rt<<1|1]);
sum2[rt]=min(sum2[rt<<1],sum2[rt<<1|1]);
}void change(int a,int b)
pushdown(l,r,rt);
int mid=(l+r)/2;
if(mid>=l) upda(l,r,l,mid,rt<<1);
if(mid+1<=r) upda(l,r,mid+1,r,rt<<1|1);
sum1[rt]=max(sum1[rt<<1],sum1[rt<<1|1]);
sum2[rt]=min(sum2[rt<<1],sum2[rt<<1|1]);
}void negate(int a,int b)
pushdown(l,r,rt);
int ans=-1e9;
int mid=(l+r)/2;
if(mid>=l) ans=max(ans,query(l,r,l,mid,rt<<1));
if(mid+1<=r) ans=max(ans,query(l,r,mid+1,r,rt<<1|1));
return ans;
}void query(int a,int b)
build(2,n,1);
char s[20];
while(1)
}return 0;
}
poj 3237 樹鏈剖分 線段樹
題意 給一棵樹,三種操作。將第i條邊的權值改為v,將a到b的路徑上的邊的權值全部取反,求a到b路徑上邊的權值的最大值。思路 明顯的樹鏈剖分,加上線段樹的操作。因為有取反的操作所以每個區間要記錄最大值和最小值。查詢兩點間的路徑時,用求公共祖先的方式去求。include include includec...
樹鏈剖分 線段樹 POJ3237 權值在邊 模板
include include include include include include include include includeusing namespace std const int maxn 100010 struct edgeedge maxn 2 int head maxn ...
poj 3237 樹鏈剖分
對樹有三種操作 q a b 詢問a b路徑的最大值 n a b 對a b路徑上的數進行取反操作 a a c a b 將第a條邊的值改為b 對於取反操作,記錄區間的最大和最小值和標記k,更新線段即可。pragma comment linker,stack 1024000000,1024000000 i...