POJ 3237 Tree /BZOJ 2157旅遊 -- 樹鏈剖分邊權處理+取反

類似SPOJ QTREE模板題,還是要注意跳過LCA!!!(因爲用最深的點權維護邊權,LCA其實是上一個點的邊權,不管update還是query)

只不過多了個取相反數操作

關於區間取相反數,如果是維護區間和,就加個負號;但如果是維護最大值,應該最大值最小值互換

 

註釋部分,表示按位取反如何維護最值(與本題無關)

POJ 3237 Tree

#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 100000+10;
typedef long long ll; 
const int inf=0x3f3f3f3f;
int w[maxn];
int N, Q;

struct
{
    int to,next,w;    
}e[maxn<<2];

int head[maxn<<1],edgeNum;

struct
{
	int u,v;
}edge[maxn<<1];

void add(int u,int v,int w)
{
    e[edgeNum].next = head[u];
    e[edgeNum].to = v;
    e[edgeNum].w=w;
    head[u] = edgeNum++;
}

/*-------------------------樹剖------------------------------*/
int deep[maxn],fa[maxn],siz[maxn],son[maxn];
void dfs1(int u,int pre,int d)
{
    deep[u] = d;
    fa[u] = pre;
    siz[u] = 1;
    son[u] = 0;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v = e[i].to;
        if(v!=pre)
        {
            dfs1(v,u,d+1);
            siz[u] += siz[v];
            if(siz[v]>siz[son[u]])
                son[u] = v;
        }
    }
}

int top[maxn],id[maxn],rk[maxn],cnt;

void dfs2(int u,int t)
{
    top[u] = t;
    id[u] = ++cnt;
    rk[cnt] = u;
    if(!son[u]) return;

    dfs2(son[u],t);

    for(int i=head[u];~i;i=e[i].next)
    {
        int v = e[i].to;
        if(v!=son[u]&&v!=fa[u])
            dfs2(v,v);
    }
}
/*-------------------------樹剖------------------------------*/

/*-------------------------線段樹------------------------------*/
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2],neg[maxn<<2],maxv[maxn<<2],minv[maxn<<2],add1[maxn<<2],mult[maxn<<2];//取反標記 
void pushup(int rt)
{
//    sum[rt] = (sum[rt<<1] + sum[rt<<1|1]);
    maxv[rt] =max(maxv[rt<<1],maxv[rt<<1|1]);
    minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
    
}


void pushdown(int rt,int l,int r)
{
	if(neg[rt]){
		//異或 
		neg[rt<<1]^=1;
		neg[rt<<1|1]^=1;
		swap(minv[rt<<1],maxv[rt<<1]);
		minv[rt<<1]=-minv[rt<<1];
		maxv[rt<<1]=-maxv[rt<<1];
		swap(minv[rt<<1|1],maxv[rt<<1|1]);
		minv[rt<<1|1]=-minv[rt<<1|1];
		maxv[rt<<1|1]=-maxv[rt<<1|1];
		neg[rt]=0;
	}
//    if(add1[rt]||mult[rt]!=1){
//    	add1[rt<<1] *= mult[rt],   add1[rt<<1] += add1[rt];
//    add1[rt<<1|1] *= mult[rt], add1[rt<<1|1] += add1[rt];
//    mult[rt<<1] *= mult[rt];
//    mult[rt<<1|1] *= mult[rt];
//
//    sum[rt<<1] *= mult[rt], sum[rt<<1] += add1[rt] * l;
//    sum[rt<<1|1] *= mult[rt], sum[rt<<1|1] += add1[rt] * r;
//
//    add1[rt] = 0;
//    mult[rt] = 1;
//	}
}

void build(int l,int r,int rt)//單點更新 
{
   
    {
//        sum[rt] = 0;
        maxv[rt]=0;
        minv[rt]=0;
        neg[rt]=0;
         if(l==r)return ;
    }
    int m = l + r >> 1;
        build(lson);
        build(rson);
   // pushup(rt);
}


void change(int val,int q,int l,int r,int rt)//單點更新 
{
    if(l==r)
    {
//        sum[rt] = val;
        maxv[rt]=val;
        minv[rt]=val;
        neg[rt]=0;
        return ;
    }
    int m = l + r >> 1;
    pushdown(rt,m-l+1,r-m);
    if(q<=m)
        change(val,q,lson);
    else
        change(val,q,rson);
    pushup(rt);
}

void update2(int L,int R,int l,int r,int rt)
{
    if(L <= l && r <= R)
    {
    	neg[rt]^=1;
//        mult[rt]*=-1,add1[rt]*=-1,add1[rt] +=-1;
       //sum[rt] =-sum[rt];
       //cout<<maxv[rt]<<" "<<minv[rt]<<endl;
       swap(maxv[rt],minv[rt]);
       maxv[rt]=-maxv[rt],minv[rt]=-minv[rt];
       //cout<<maxv[rt]<<" "<<minv[rt]<<endl;
        return ;
    }
    int m = l + r >> 1;
    pushdown(rt,m-l+1,r-m);
    if(L<=m)
        update2(L,R,lson);
    if(R>m)
        update2(L,R,rson);
    pushup(rt);
}

int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
        return sum[rt];
    int m = l + r >> 1,ans = 0;
 pushdown(rt,m-l+1,r-m);
    if(L<=m)
        ans = (ans + query(L,R,lson));
    if(R>m)
        ans = (ans + query(L,R,rson));
    return ans;
}

int querymax(int L,int R,int l,int r,int rt){
    if (L<=l&&r<=R){
    	return maxv[rt];
	}
    int m=(l+r)>>1,ans=-inf;//注意負數① 
   pushdown(rt,m-l+1,r-m);
    if (L<=m)ans=max(ans,querymax(L,R,lson));
    if (R>m)ans=max(ans,querymax(L,R,rson));
    pushup(rt);
    return ans;
}
/*-------------------------線段樹------------------------------*/

/*-----------------------樹剖加線段樹--------------------------*/
void update2(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        update2(id[top[x]],id[x],1,cnt,1);
        x = fa[top[x]];
    }
   // if(x==y)return ; 
    if(deep[x]>deep[y])
        swap(x,y);
    update2(id[x]+1,id[y],1,cnt,1);//跳過LCA(深度小的),所以+1 
}


int query(int x,int y)
{
    int ans = 0;
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]])
            swap(x,y);
        ans = (ans + query(id[top[x]],id[x],1,cnt,1));//這裏下標從1開始 
        x = fa[top[x]];
    }
    if(deep[x]>deep[y])
        swap(x,y);
    ans = (ans + query(id[x]+1,id[y],1,cnt,1));//跳過LCA(深度小的),所以+1 
    return ans;
}

int querymax(int x,int y)
{
    int ans =-inf;//注意負數② 
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]])
            swap(x,y);
        ans = max(ans ,querymax(id[top[x]],id[x],1,cnt,1)); 
        x = fa[top[x]];
    }
   // if(x==y)return ans;
    if(deep[x]>deep[y])
        swap(x,y);
    ans = max(ans ,querymax(id[x]+1,id[y],1,cnt,1));//跳過LCA(深度小的),所以+1 
    return ans;
}
/*-----------------------樹剖加線段樹--------------------------*/

void init()
{
    memset(head,-1,sizeof(head));
    cnt = edgeNum = 0;
    memset(son,0,sizeof(son)) ;//這個也要初始化 
}

int u, v, l, r,z;
int main()
{   
   	int T;
	scanf("%d",&T) ;
	while(T--){
	   	scanf("%d",&N);
   	    init();
   	for(int i=1;i<N;++i)
	{
		//w[i] = 0;
		scanf("%d%d%d",&u,&v,&w[i]);
		edge[i].u=u;
        edge[i].v=v;//真正的邊數 
		add(u,v,w[i]);//邊數*2 
		add(v,u,w[i]);
		
	}
	
	dfs1(1,0,0);
	dfs2(1,1);
	//build(1,N,1);//也可不build
	for(int i=1;i<N;i++){
		int tmp=deep[edge[i].u] > deep[edge[i].v] ? edge[i].u : edge[i].v;
		change(w[i],id[tmp],1,N,1);
	}

	
	while(1)
	{
		char p[10];
		scanf("%s",p);
		if(p[0]=='D')break;//這裏就要break! 
		scanf("%d%d",&r,&z);
		if(p[0]=='C'){
			r=deep[edge[r].u] > deep[edge[r].v] ? edge[r].u : edge[r].v;
			change(z,id[r],1,N,1) ;
		}
		else if(p[0]=='Q')printf("%d\n",querymax(r,z));
		else if(p[0]=='N') update2(r,z);
		

	}
	   }

    return 0;
}

②BZOJ 2157 旅遊

多了兩個詢問最大最小值而已

#include <stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn = 200000+10;
typedef long long ll; 
const int inf=0x3f3f3f3f;
int w[maxn];
int N, Q;

struct
{
    int to,next,w;    
}e[maxn<<2];

int head[maxn<<1],edgeNum;

struct
{
	int u,v;
}edge[maxn<<1];

void add(int u,int v,int w)
{
    e[edgeNum].next = head[u];
    e[edgeNum].to = v;
    e[edgeNum].w=w;
    head[u] = edgeNum++;
}

/*-------------------------樹剖------------------------------*/
int deep[maxn],fa[maxn],siz[maxn],son[maxn];
void dfs1(int u,int pre,int d)
{
    deep[u] = d;
    fa[u] = pre;
    siz[u] = 1;
    son[u] = 0;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v = e[i].to;
        if(v!=pre)
        {
            dfs1(v,u,d+1);
            siz[u] += siz[v];
            if(siz[v]>siz[son[u]])
                son[u] = v;
        }
    }
}

int top[maxn],id[maxn],rk[maxn],cnt;

void dfs2(int u,int t)
{
    top[u] = t;
    id[u] = ++cnt;
    rk[cnt] = u;
    if(!son[u]) return;

    dfs2(son[u],t);

    for(int i=head[u];~i;i=e[i].next)
    {
        int v = e[i].to;
        if(v!=son[u]&&v!=fa[u])
            dfs2(v,v);
    }
}
/*-------------------------樹剖------------------------------*/

/*-------------------------線段樹------------------------------*/
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2],neg[maxn<<2],maxv[maxn<<2],minv[maxn<<2],add1[maxn<<2],mult[maxn<<2];//取反標記 
void pushup(int rt)
{
     sum[rt] = (sum[rt<<1] + sum[rt<<1|1]);
    maxv[rt] =max(maxv[rt<<1],maxv[rt<<1|1]);
    minv[rt]=min(minv[rt<<1],minv[rt<<1|1]);
    
}


void pushdown(int rt,int l,int r)
{
	if(neg[rt]){
		//異或 
		neg[rt<<1]^=1;
		neg[rt<<1|1]^=1;
		sum[rt<<1]=-sum[rt<<1];
		sum[rt<<1|1]=-sum[rt<<1|1];
		swap(minv[rt<<1],maxv[rt<<1]);
		minv[rt<<1]=-minv[rt<<1];
		maxv[rt<<1]=-maxv[rt<<1];
		swap(minv[rt<<1|1],maxv[rt<<1|1]);
		minv[rt<<1|1]=-minv[rt<<1|1];
		maxv[rt<<1|1]=-maxv[rt<<1|1];
		neg[rt]=0;
	}

}

void build(int l,int r,int rt)//單點更新 
{
   
    {
       sum[rt] = 0;
        maxv[rt]=0;
        minv[rt]=0;
        neg[rt]=0;
         if(l==r)return ;
    }
    int m = l + r >> 1;
        build(lson);
        build(rson);
   // pushup(rt);
}


void change(int val,int q,int l,int r,int rt)//單點更新 
{
    if(l==r)
    {
        sum[rt] = val;
        maxv[rt]=val;
        minv[rt]=val;
        neg[rt]=0;//不會變成相反數了! 
        return ;
    }
    int m = l + r >> 1;
    pushdown(rt,m-l+1,r-m);
    if(q<=m)
        change(val,q,lson);
    else
        change(val,q,rson);
    pushup(rt);
}

void update2(int L,int R,int l,int r,int rt)
{
    if(L <= l && r <= R)
    {
    	neg[rt]^=1;
       sum[rt] =-sum[rt];
       swap(maxv[rt],minv[rt]);
       maxv[rt]=-maxv[rt],minv[rt]=-minv[rt];
        return ;
    }
    int m = l + r >> 1;
    pushdown(rt,m-l+1,r-m);
    if(L<=m)
        update2(L,R,lson);
    if(R>m)
        update2(L,R,rson);
    pushup(rt);
}

int query(int L,int R,int l,int r,int rt)
{
    if(L<=l&&r<=R)
        return sum[rt];
    int m = l + r >> 1,ans = 0;
 pushdown(rt,m-l+1,r-m);
    if(L<=m)
        ans = (ans + query(L,R,lson));
    if(R>m)
        ans = (ans + query(L,R,rson));
    //pushup(rt);
    return ans;
}

int querymax(int L,int R,int l,int r,int rt){
    if (L<=l&&r<=R){
    	return maxv[rt];
	}
    int m=(l+r)>>1,ans=-inf;//注意負數① 
   pushdown(rt,m-l+1,r-m);
    if (L<=m)ans=max(ans,querymax(L,R,lson));
    if (R>m)ans=max(ans,querymax(L,R,rson));
    pushup(rt);
    return ans;
}

int querymin(int L,int R,int l,int r,int rt){
    if (L<=l&&r<=R){
    	return minv[rt];
	}
    int m=(l+r)>>1,ans=inf;
   pushdown(rt,m-l+1,r-m);
    if (L<=m)ans=min(ans,querymin(L,R,lson));
    if (R>m)ans=min(ans,querymin(L,R,rson));
    pushup(rt);
    return ans;
}
/*-------------------------線段樹------------------------------*/

/*-----------------------樹剖加線段樹--------------------------*/
void update2(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])
            swap(x,y);
        update2(id[top[x]],id[x],1,cnt,1);
        x = fa[top[x]];
    }
   // if(x==y)return ; 
    if(deep[x]>deep[y])
        swap(x,y);
    update2(id[x]+1,id[y],1,cnt,1);
}


int query(int x,int y)
{
    int ans = 0;
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]])
            swap(x,y);
        ans = (ans + query(id[top[x]],id[x],1,cnt,1));//這裏下標從1開始 
        x = fa[top[x]];
    }
    if(deep[x]>deep[y])
        swap(x,y);
    ans = (ans + query(id[x]+1,id[y],1,cnt,1));
    return ans;
}

int querymax(int x,int y)
{
    int ans =-inf;//注意負數② 
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]])
            swap(x,y);
        ans = max(ans ,querymax(id[top[x]],id[x],1,cnt,1)); 
        x = fa[top[x]];
    }
   // if(x==y)return ans;
    if(deep[x]>deep[y])
        swap(x,y);
    ans = max(ans ,querymax(id[x]+1,id[y],1,cnt,1));//跳過LCA(深度小的),所以+1 
    return ans;
}

int querymin(int x,int y)
{
    int ans =inf; 
    while(top[x] != top[y])
    {
        if(deep[top[x]] < deep[top[y]])
            swap(x,y);
        ans = min(ans ,querymin(id[top[x]],id[x],1,cnt,1)); 
        x = fa[top[x]];
    }
   // if(x==y)return ans;
    if(deep[x]>deep[y])
        swap(x,y);
    ans = min(ans ,querymin(id[x]+1,id[y],1,cnt,1));//跳過LCA(深度小的),所以+1 
    return ans;
}
/*-----------------------樹剖加線段樹--------------------------*/

void init()
{
    memset(head,-1,sizeof(head));
    cnt = edgeNum = 0;
    memset(son,0,sizeof(son)) ;//這個也要初始化!!! 
}

int u, v, l, r,z;
int main()
{   
   	int T=1;
	while(T--){
	   	scanf("%d",&N);
   	    init();
   	for(int i=1;i<N;++i)
	{

		scanf("%d%d%d",&u,&v,&w[i]);
		++u,++v;//編號+1 
		edge[i].u=u;
        edge[i].v=v;//真正的邊數 
		add(u,v,w[i]);//邊數*2 
		add(v,u,w[i]);
		
	}
	
	dfs1(1,0,0);
	dfs2(1,1);
	build(1,N,1);//可不要
	for(int i=1;i<N;i++){
		int tmp=deep[edge[i].u] > deep[edge[i].v] ? edge[i].u : edge[i].v;
		change(w[i],id[tmp],1,N,1);
	}
	scanf("%d",&Q);
	
	while(Q--)
	{
		char p[10];
		scanf("%s",p);
		if(p[0]=='D')break;//這裏就要break! 
		scanf("%d%d",&r,&z);
		r++,z++;//點編號從1開始 
		if(p[0]=='C'){
			r--,z--;//那兩個不是點編號 
			r=deep[edge[r].u] > deep[edge[r].v] ? edge[r].u : edge[r].v;
			change(z,id[r],1,N,1) ;
		}
		else if(p[0]=='N') update2(r,z);
		else if(p[0]=='S')printf("%d\n",query(r,z));
		else if(p[1]=='A')printf("%d\n",querymax(r,z));
		else if(p[1]=='I')printf("%d\n",querymin(r,z));
		
		

	}
	   }

    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章