poj 3237 樹鏈剖分 線段樹

2021-07-05 15:39:09 字數 1539 閱讀 8164

題意就是給你一棵樹,每條邊上都有權值,有三種操作,把某條邊的權值變成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...