題意:給一棵樹,三種操作。將第i條邊的權值改為v,將a到b的路徑上的邊的權值全部取反,求a到b路徑上邊的權值的最大值。
思路:明顯的樹鏈剖分,加上線段樹的操作。因為有取反的操作所以每個區間要記錄最大值和最小值。查詢兩點間的路徑時,用求公共祖先的方式去求。
#include#include#includeconst int n=101000;
const int inf=0x3fffffff;
using namespace std;
int head[n],num,son[n],sz[n],father[n],dep[n],idx,a[n],cot[n],ti[n],top[n];
struct edge
e[n*4];
void addedge(int x,int y,int w)
int max(int a,int b)
int min(int a,int b)
//******************樹鏈剖分****************************
void find_son(int u,int fa)
}void find_time(int u,int fa)
}//***********************線段樹*********************
struct tree
t[n*10];
void up(int id)
void buildtree(int l,int r,int id)
int mid=(l+r)>>1,li=id<<1,ri=li|1;
buildtree(l,mid,li);
buildtree(mid+1,r,ri);
up(id);
}void fan(int id)
void negate(int l,int r,int id)//取反操作
int mid=(t[id].l+t[id].r)>>1,li=id<<1,ri=li|1;
if(t[id].flag)
if(r<=mid)negate(l,r,li);
else if(l>mid)negate(l,r,ri);
else
up(id);
}void insert(int x,int id,int w)//更新x的值
int mid=(t[id].l+t[id].r)>>1,li=id<<1,ri=li|1;
if(t[id].flag)
fan(id);
if(x<=mid)insert(x,li,w);
else insert(x,ri,w);
up(id);
}int find(int l,int r,int id)//找最大值
int mid=(t[id].l+t[id].r)>>1,li=id<<1,ri=li|1;
if(t[id].flag)
fan(id);
if(r<=mid)return find(l,r,li);
else if(l>mid)return find(l,r,ri);
else return max(find(l,mid,li),find(mid+1,r,ri));
up(id);
}int lca(int x,int y)//x到y路徑上的最大值
void lca(int x,int y)//x到y路徑權值取反
int main()
else if(str[0]=='n')
lca(x,y);
else
printf("%d\n",lca(x,y));
} }return 0;
}
poj 3237 樹鏈剖分 線段樹
題意就是給你一棵樹,每條邊上都有權值,有三種操作,把某條邊的權值變成v,把點a到點b之間的路徑上的邊的權值都乘上 1,求a到b的路徑上的最大值。其實這題的線段樹要比樹鏈剖分難寫,首先,因為有乘 1的操作,所以不光要維護最大值,還要維護最小值,這樣在乘 1後,最大值就可以直接根據最小值得到,當然,延遲...
樹鏈剖分 線段樹 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...