您的位置:首页 > 其它

poj 3237 Tree(树链剖分,线段树)

2016-02-10 22:56 381 查看
Tree

Time Limit: 5000MSMemory Limit: 131072K
Total Submissions: 7268Accepted: 1969
Description

You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edges are numbered 1 through N − 1. Each edge is associated with a weight. Then you are to execute a series of instructions on the tree. The instructions can be one of the following forms:

CHANGE
i v
Change the weight of the ith edge to v
NEGATE
a b
Negate the weight of every edge on the path from a to b
QUERY
a b
Find the maximum weight of edges on the path from a to b
Input

The input contains multiple test cases. The first line of input contains an integer t (t ≤ 20), the number of test cases. Then follow the test cases.

Each test case is preceded by an empty line. The first nonempty line of its contains N (N ≤ 10,000). The next N − 1 lines each contains three integers a, b and c, describing an edge connecting nodes a and b with weight c. The edges are numbered in the order they appear in the input. Below them are the instructions, each sticking to the specification above. A lines with the word “
DONE
” ends the test case.

Output

For each “
QUERY
” instruction, output the result on a separate line.

Sample Input

1

3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE

Sample Output

1
3

Source

POJ Monthly--2007.06.03, Lei, Tao

【思路】

树链剖分,线段树。

又练了一边线段树<_<,bug满天飞T^T,线段树还得再做点题。

线段树:维护mx mn分别代表线段最大最小值,对于NEGATE操作打一个f标记,作用时直接将mx mn取负后交换即可。注意一下pushdown和maintain。

【代码】

#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;

const int N = 50000+10;
const int INF = 1e9;

struct Node { int l,r,mx,mn,f;
}T[N<<1];
struct Edge {
int u,v,w;
Edge(int u=0,int v=0,int w=0) :u(u),v(v),w(w) {};
};
int n,q,z,d
[3];
vector<Edge> es;
vector<int> g
;

void adde(int u,int v,int w) {
es.push_back(Edge(u,v,w));
int m=es.size();
g[u].push_back(m-1);
}
//INIT
int top
,son
,dep
,fa
,siz
,w
;
void dfs1(int u) {
son[u]=0; siz[u]=1;
for(int i=0;i<g[u].size();i++) {
int v=es[g[u][i]].v;                                //1
if(v!=fa[u]) {
fa[v]=u , dep[v]=dep[u]+1;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>siz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int tp) {
top[u]=tp; w[u]=++z;
if(son[u]) dfs2(son[u],tp);
for(int i=0;i<g[u].size();i++) {
int v=es[g[u][i]].v;
if(v!=fa[u] && v!=son[u]) dfs2(v,v);
}
}
//SEGMENT TREE
//标记 该结点已被作用而子结点仍未作用
//pushdown 作用于访问节点 即只要访问就pushdown
void pushdown(int u) {    //下传标记 同时作用于子结点
if(T[u].f && T[u].l<T[u].r) {
int lc=u<<1,rc=lc|1;
T[u].f=0;
T[lc].f^=1 ,T[rc].f^=1;
int t;
t=T[lc].mn,T[lc].mn=-T[lc].mx,T[lc].mx=-t;
t=T[rc].mn,T[rc].mn=-T[rc].mx,T[rc].mx=-t;
}
}
void maintain(int u) {
T[u].mx=max(T[u<<1].mx,T[u<<1|1].mx);
T[u].mn=min(T[u<<1].mn,T[u<<1|1].mn);
}
void build(int u,int L,int R) {
T[u].l=L,T[u].r=R;
T[u].mn=INF , T[u].mx=-INF , T[u].f=0;
if(L==R) return ;                                        //2
int M=(L+R)>>1;
build(u<<1,L,M) , build(u<<1|1,M+1,R);
}
void change(int u,int r,int x) {
pushdown(u);                                            //6
if(T[u].l==T[u].r) T[u].mn=T[u].mx=x;
else {
int M=(T[u].l+T[u].r)>>1;                            //3
if(r<=M) change(u<<1,r,x);
else change(u<<1|1,r,x);
maintain(u);
}
}
void Negate(int u,int L,int R) {
pushdown(u);
if(L<=T[u].l && T[u].r<=R) {//打标记 同时作用于当前结点
T[u].f=1;
int t; t=T[u].mn,T[u].mn=-T[u].mx,T[u].mx=-t;        //4
}
else {
int M=(T[u].l+T[u].r)>>1;
if(L<=M) Negate(u<<1,L,R);
if(M<R) Negate(u<<1|1,L,R);
maintain(u);
}
}
int query(int u,int L,int R) {
pushdown(u);
if(L<=T[u].l && T[u].r<=R) return T[u].mx;
else {
int M=(T[u].l+T[u].r)>>1;
int ans=-INF;
if(L<=M) ans=max(ans,query(u<<1,L,R));
if(M<R) ans=max(ans,query(u<<1|1,L,R));
return ans;
}
}

//树链剖分
void modify(int u,int v) {
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
Negate(1,w[top[u]],w[u]);
u=fa[top[u]];
}
if(u==v) return ;
if(dep[u]>dep[v]) swap(u,v);
Negate(1,w[son[u]],w[v]);                                //5
}
int query(int u,int v) {
int mx=-INF;
while(top[u]!=top[v]) {
if(dep[top[u]]<dep[top[v]]) swap(u,v);
mx=max(mx,query(1,w[top[u]],w[u]));
u=fa[top[u]];
}
if(u==v) return mx;
if(dep[u]>dep[v]) swap(u,v);
mx=max(mx,query(1,w[son[u]],w[v]));
return mx;
}

void read(int& x) {
char c=getchar();
while(!isdigit(c)) c=getchar();
x=0;
while(isdigit(c))
x=x*10+c-'0' , c=getchar();
}
int main() {
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
int T; read(T);
while(T--) {
read(n);
z=0; es.clear();
FOR(i,0,n) g[i].clear();
int u,v,c;
FOR(i,1,n-1) {
read(u),read(v),read(c);
d[i][0]=u,d[i][1]=v,d[i][2]=c;
adde(u,v,c),adde(v,u,c);
}
dfs1(1),dfs2(1,1);
build(1,1,z);
FOR(i,1,n-1) {
if(dep[d[i][1]]<dep[d[i][0]]) swap(d[i][0],d[i][1]);
change(1,w[d[i][1]],d[i][2]);
}
char s[10];
while(scanf("%s",s)==1 && s[0]!='D') {
read(u),read(v);
if(s[0]=='C') change(1,w[d[u][1]],v);
else if(s[0]=='N') modify(u,v);
else printf("%d\n",query(u,v));
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: