poj 3237 加强版 query on a tree 树链剖分

链接:

http://www.spoj.pl/problems/QTREE/

http://poj.org/problem?id=3237


题意:一棵树,两种更新操作,改变一条边的边权,将a ->b路径上的所有边权取反,询问一条路径上的最大边权

都是典型的树链剖分,下面一题是上面的加强版,还要在树上进行成段更新,其实也不难。

只是区间还要再记录一个最小值,因为取反操作的话会使得区间的最大值和最小值互换。

然后就是树链剖分的老套路,如果是重链,在线段树中更新,否则直接改变边权。

线段树中下放懒惰标记的时候写漏了,调了许久,囧爆了。。。。

好像还可以用动态树实现吧,概念都看懂了,只是没实践过,改天去学了再贴上来吧

下面是这两题的代码,我的代码有点搓 - -,观看请慎重,以免伤了眼*_*

spoj  375  query on a tree

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 20010;
const int inf = ~0u>>2;
int M[maxn<<2];
struct node{
    int s,t,w,next;
}edge[maxn*2];
int E,n;
int size[maxn] , fa[maxn] , heavy[maxn] , head[maxn] , dep[maxn] , rev[maxn] , num[maxn] , cost[maxn];
int Seg_size;
inline void Max(int &x,int y){if(x<y) x=y;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void add_edge(int s,int t,int w)
{
    edge[E].w=w;
    edge[E].s=s;
    edge[E].t=t;
    edge[E].next=head[s];
    head[s]=E++;
}
void dfs(int u,int f)
{
    int mx=-1,e=-1;
    size[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].t;
        if(v==f) continue;
        dep[v]=dep[u]+1;
        rev[v]=i^1;
        dfs(v,u);
        size[u]+=size[v];
        if(size[v]>mx)
        {
            mx=size[v];
            e=i;
        }
    }
    heavy[u]=e;
    if(e!=-1)  fa[edge[e].t]=u;
}
inline void pushup(int rt){
    M[rt]=max(M[rt<<1],M[rt<<1|1]);
}
void build(int l,int r,int rt){
    M[rt]=inf;
    if(l==r){
        return ;
    }
    int m=(l+r)>>1;
    build(lson);
    build(rson);
}
void update(int p,int val,int l,int r,int rt){
    if(l==r){
       M[rt]=val;
       return ;
    }
    int m=(l+r)>>1;
    if(p<=m) update(p,val,lson);
    else update(p,val,rson);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
    if(L<=l&&r<=R){
        return M[rt];
    }
    int m=(l+r)>>1;
    int ret=0;
    if(L<=m) ret=max(ret,query(L,R,lson));
    if(R>m) ret=max(ret,query(L,R,rson));
    return ret;
}
void prepare()
{
    build(1,n-1,1);
    memset(num,-1,sizeof(num));
    dep[0]=0;Seg_size=0;
    for(int i=0;i<n;i++) fa[i]=i;
    dfs(0,0);    
    for(int i=0;i<n;i++)
    {
        if(heavy[i]==-1)
        {
            int pos=i;
            while(pos && edge[heavy[edge[rev[pos]].t]].t == pos)
            {
                int t=rev[pos];
                num[t]=num[t^1]=++Seg_size;
                update(Seg_size,edge[t].w,1,n-1,1);
                pos=edge[t].t;
            }
        }
    }
}
void change(int edge_id,int val)
{
    if(num[edge_id]==-1) edge[edge_id].w=edge[edge_id^1].w=val;
    else update(num[edge_id],val,1,n-1,1);
}
int calc(int u,int lca)
{
    int ans=-inf;int vi=0;
    while(u!=lca)
    {
        vi++;
        if(vi==10) break;
        int r=rev[u];
        if(num[r]==-1) Max(ans,edge[r].w),u=edge[r].t;
        else 
        {
            int p=fa[u];
            if(dep[p] < dep[lca]) p=lca;
            int l=num[r];
            int r=num[heavy[p]];
            Max(ans,query(l,r,1,n-1,1));
            u=p;
        }
    }
    return ans;
}
int lca(int u,int v)
{
    while(1)
    {
        int a=find(u),b=find(v);
        if(a==b) return dep[u] < dep[v] ? u : v;//a,b在同一条重链上
        else if(dep[a]>=dep[b]) u=edge[rev[a]].t;
        else v=edge[rev[b]].t;
    }
}
int solve(int u,int v)
{
    int p=lca(u,v);
    return max(calc(u,p),calc(v,p));
}
int main()
{
    int t,i,a,b,c;
    scanf("%d",&t);
    while(t--)
    {
        memset(head,-1,sizeof(head));
        E=0;
        scanf("%d",&n);
        for(i=0;i<n-1;i++)
        {
            scanf("%d%d%d",&a,&b,&c);a--;b--;
            add_edge(a,b,c);
            add_edge(b,a,c);
        }
        prepare();
        char op[20];
        while(scanf("%s",op)!=EOF && strcmp(op,"DONE"))
        {
            if(op[0]=='C')
            {
                scanf("%d%d",&a,&c);
                change((a-1)*2,c);
            }
            else 
            {
                scanf("%d%d",&a,&b);
                printf("%d\n",solve(a-1,b-1));
            }
        }
    }
    return 0;
}
/*
1
3
1 2 1
2 3 2
QUERY 1 2
CHANGE 1 3
QUERY 1 2
DONE
1
3
1
7
1 2 1
1 3 2
2 4 3
2 5 4
3 6 5
3 7 6
Query 1 7
*/



poj 3237

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 100010;
const int inf = ~0u>>2;
int M[maxn<<2];
int Mi[maxn<<2];
int col[maxn<<2];
struct node{
	int s,t,w,next;
}edge[maxn*2];
int E,n;
int size[maxn] , fa[maxn] , heavy[maxn] , head[maxn] , dep[maxn] , rev[maxn] , num[maxn] , cost[maxn];
int Seg_size;
inline void Max(int &x,int y){if(x<y) x=y;}
inline int max(int a,int b){return a>b?a:b;}
inline int min(int a,int b){return a>b?b:a;}
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
void add_edge(int s,int t,int w){
	edge[E].w=w;
	edge[E].s=s;
	edge[E].t=t;
	edge[E].next=head[s];
	head[s]=E++;
}
void dfs(int u,int f){
	int mx=-1,e=-1;
	size[u]=1;
	for(int i=head[u];i!=-1;i=edge[i].next){
		int v=edge[i].t;
		if(v==f) continue;
		dep[v]=dep[u]+1;
		rev[v]=i^1;
		dfs(v,u);
		size[u]+=size[v];
		if(size[v]>mx){
			mx=size[v];
			e=i;
		}
	}
	heavy[u]=e;
	if(e!=-1)  fa[edge[e].t]=u;
}
void build(int l,int r,int rt){
	Mi[rt]=inf;
	M[rt]=-inf;
	col[rt]=0;
	if(l==r){
		return ;
	}
	int m=(l+r)>>1;
	build(lson);
	build(rson);
}
inline void pushup(int rt){
	M[rt]=max(M[rt<<1],M[rt<<1|1]);
	Mi[rt]=min(Mi[rt<<1],Mi[rt<<1|1]);
}
void make(int rt){
	int tmp=Mi[rt];
	Mi[rt]=-M[rt];
	M[rt]=-tmp;
}
void pushdown(int rt){
	if(col[rt]){
       col[rt<<1]^=1;
	   make(rt<<1);
	   col[rt<<1|1]^=1;
	   make(rt<<1|1);
	   col[rt]=0;//很久没写线段树,连这个都忘了,囧
	}
}
void update(int p,int val,int l,int r,int rt){
	if(l==r){
	   Mi[rt]=M[rt]=val;
	   return ;
	}
	pushdown(rt);
	int m=(l+r)>>1;
	if(p<=m) update(p,val,lson);
	else update(p,val,rson);
	pushup(rt);
}
void justdoit(int L,int R,int l,int r,int rt){
	//printf("L=%d R=%d l=%d r=%d\n",L,R,l,r);
	if(L<=l&&r<=R){
		col[rt]^=1;
		make(rt);
		return ;
	}
	pushdown(rt);
	int m=(l+r)>>1;
	if(L<=m) justdoit(L,R,lson);
	if(R>m) justdoit(L,R,rson);
	pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
	if(L<=l&&r<=R){
		return M[rt];
	}
	pushdown(rt);
	int m=(l+r)>>1;
	int ret=-inf;
	if(L<=m) ret=max(ret,query(L,R,lson));
	if(R>m) ret=max(ret,query(L,R,rson));
	return ret;
}
void prepare(){
	build(1,n-1,1);
	memset(num,-1,sizeof(num));
	dep[0]=0;Seg_size=0;
	for(int i=0;i<n;i++) fa[i]=i;
	dfs(0,0);	
	for(int i=0;i<n;i++){
		if(heavy[i]==-1)	{
			int pos=i;
			while(pos && edge[heavy[edge[rev[pos]].t]].t == pos)	{
				int t=rev[pos];
				num[t]=num[t^1]=++Seg_size;
				update(Seg_size,edge[t].w,1,n-1,1);
				pos=edge[t].t;
			}
		}
	}
}
void change(int edge_id,int val){
	if(num[edge_id]==-1) edge[edge_id].w=edge[edge_id^1].w=val;
	else update(num[edge_id],val,1,n-1,1);
}
int calc(int u,int lca){
	int ans=-inf;
    while(u!=lca){
		int r=rev[u];
		if(num[r]==-1) Max(ans,edge[r].w),u=edge[r].t;
		else {
			int p=fa[u];
			if(dep[p] < dep[lca]) p=lca;
			int l=num[r];
			int r=num[heavy[p]];
			Max(ans,query(l,r,1,n-1,1));
			u=p;
		}
	}
	return ans;
}
void gao(int u,int lca){
	while(u!=lca){
		int r=rev[u];
		if(num[r]==-1) edge[r].w=edge[r^1].w=-edge[r].w,u=edge[r].t;
		else{
			int p=fa[u];
			if(dep[p] < dep[lca]) p=lca;
			int l=num[r];
			int r=num[heavy[p]];
			//printf("l=%d r=%d\n",l,r);
			justdoit(l,r,1,n-1,1);
			u=p;
		}
	}
}
int lca(int u,int v){
	while(1){
		int a=find(u),b=find(v);
		if(a==b) return dep[u] < dep[v] ? u : v;//a,b在同一条重链上
		else if(dep[a]>=dep[b]) u=edge[rev[a]].t;
		else v=edge[rev[b]].t;
	}
}
int solve(int u,int v){
	int p=lca(u,v);
	return max(calc(u,p),calc(v,p));
}
void sol(int u,int v){
	int p=lca(u,v);//printf("p=%d\n",p);
	gao(u,p);gao(v,p);
}
int main(){
	int t,i,a,b,c;
	scanf("%d",&t);
	while(t--)	{
		memset(head,-1,sizeof(head));
		E=0;
		scanf("%d",&n);
		for(i=0;i<n-1;i++){
			scanf("%d%d%d",&a,&b,&c);a--;b--;
			add_edge(a,b,c);
			add_edge(b,a,c);
		}
		prepare();
		char op[20];
		while(scanf("%s",op)!=EOF && strcmp(op,"DONE")){
			if(op[0]=='C'){
				scanf("%d%d",&a,&c);
				change((a-1)*2,c);
			}
			else if(op[0]=='N'){
				scanf("%d%d",&a,&b);
				if(a==b) while(1);
				sol(a-1,b-1);
			}
			else {
				
				scanf("%d%d",&a,&b);
				if(a==b) while(1);
				printf("%d\n",solve(a-1,b-1));
			}
		}
	}
	return 0;
}



你可能感兴趣的:(c,struct,tree,query,ini,Build)