HDU-5893 树链剖分+区间合并

List wants to travel

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 446    Accepted Submission(s): 101


Problem Description
A boy named List who is perfect in English. Now he wants to travel and he is making a plan. But the cost of living in same citie always changes. Now he wants to know how many different kinds of continuous same cost he has to pay for living between two cities. Can you help him? (He is so lazy to do this by himself.)
 

Input
There are multiple cases. The first line contains two positive numbers N and M(N (N<=40000) where N is the amount of cities and M (M<=50000)) is the amount of operations.Then N-1 lines where each line have 3 integers a b and c, representing that there is a bidirectionoal road between city a and city b, and the cost is c.(a != b and c <= 100000). Then there are M lines of operation. For example, "Change a b c" means changing all the costs of the road which are passed by him when he travels from city a to city b to c. "Query a b" means he wants you to tell him how many different kinds of continuous same cost he has to pay traveling from city a to city b.(if a == b, the cost is 0).
 

Output
He insure you that there is exactly one route between every two different cities.
 

Sample Input
  
  
9 3 1 2 2 2 3 1 1 7 2 1 4 2 3 5 2 3 6 1 5 8 2 5 9 3 Query 1 8 Change 2 6 3 Query 1 6
 

Sample Output
  
  
3 2
 

Source


题目链接:

题目大意:
给出一棵树上的两种操作:
1.将节点a到节点b路径上的边权全部修改为c;
2.查询节点a到节点b路径上边权的段数。

解题思路:
先进行树链剖分,将问题转化到区间上,之后统计段数是经典的线段树区间合并问题。修改操作直接修改就好了,对于查询操作,需要注意链的合并,可以先求一次a与b的LCA,之后将路径分为两段分别查询,最后看拼接处权值是否相同。

AC代码:
import java.io.*;
import java.util.*;

public class Main {
	static StreamTokenizer in=new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
	static int nextInt() throws IOException    
	{  
	    in.nextToken();    
	    return (int)in.nval;     
	}
	static String next() throws IOException    
	{  
	    in.nextToken();  
	    return in.sval;
	}
	static PrintWriter out=new PrintWriter(new OutputStreamWriter(System.out));
	static int n,m,ee,a,b,c,ct,op,co;
	static int[] aa=new int[40005];
	static int[] fa=new int[40005];
	static int[] id=new int[40005];
	static int[] top=new int[40005];
	static int[] son=new int[40005];
	static int[] dep=new int[40005];
	static int[] size=new int[40005];
	static int[] head=new int[40005];
	static int[] edge=new int[80005];
	static int[] next=new int[80005];
	static int[] cost=new int[80005];
	static int[] ll=new int[320005];
	static int[] rr=new int[320005];
	static int[] mm=new int[320005];
	static int[] sum=new int[320005];
	static void add(int a,int b,int c)
	{
		edge[ee]=b;next[ee]=head[a];
		cost[ee]=c;head[a]=ee++;
	}
	static void dfs(int u,int f,int d)  
    {  
        size[u]=1;dep[u]=d;  
        son[u]=-1;fa[u]=f;  
        int v;  
        for(int i=head[u];i!=-1;i=next[i])  
        {  
            v=edge[i];  
            if(v==f) continue;
            aa[v]=cost[i];
            dfs(v,u,d+1);  
            size[u]+=size[v]; 
            if(son[u]==-1||size[son[u]]<size[v])  
                son[u]=v;  
        }  
    }  
    static void dfs2(int u,int f,int t)  
    {  
        id[u]=++ct;top[u]=t;
        if(son[u]!=-1) dfs2(son[u],u,t);  
        int v;
        for(int i=head[u];i!=-1;i=next[i])  
        {  
            v=edge[i];  
            if(v==f||v==son[u]) continue;
            dfs2(v,u,v);  
        }  
    }
    static void prepare()  
    {  
        dfs(1,0,1);  
        ct=0;dfs2(1,0,1);
        Arrays.fill(mm,-1);
        Arrays.fill(ll,0);
        Arrays.fill(rr,0);
        Arrays.fill(sum,0);
        for(int i=1;i<=n;i++)
        	updata(id[i],id[i],1,1,n,aa[i]);
    }
    static int Query(int u,int v)  
    {
    	int p=LCA(u,v),ans=0;
    	if(dep[u]>dep[v]) { c=u;u=v;v=c;}
    	if(u==p) ans=query(v,u);
    	else
    	{
    		int co1,co2;
    		ans+=query(v,p);co1=co;
    		ans+=query(u,p);co2=co;
    		if(co1==co2) ans--;
    	}
        return ans;
    }
    static int LCA(int u,int v)
    {
    	while(top[u]!=top[v])
        {
    		a=top[u];b=top[v];
    		if(dep[a]<dep[b])
    		{
    			c=u;u=v;v=c;
    			c=a;a=b;b=c;
    		}
    		u=fa[a];
    	}
    	return dep[u]>dep[v]?v:u;
    }
    static int query(int u,int v)
    {
    	int ans=0;  
        while(top[u]!=top[v])  
        {  
            a=top[u];
            ans+=sum(id[a],id[u],1,1,n);
            co=get(id[a],1,1,n);
            if(v!=fa[a]&&co==get(id[fa[a]],1,1,n))
            	ans--;
            u=fa[a];  
        }
        if(u!=v)
        {
        	co=get(id[son[v]],1,1,n);
        	ans+=sum(id[son[v]],id[u],1,1,n);
        }
        return ans;
    }
    static void Change(int u,int v,int x)  
    {  
        while(top[u]!=top[v])  
        {  
            a=top[u];b=top[v];  
            if(dep[a]<dep[b])  
            {
                c=u;u=v;v=c;  
                c=a;a=b;b=c;  
            }
            updata(id[a],id[u],1,1,n,x);
            u=fa[a];
        }  
        if(u!=v)
        {
        	if(dep[u]>dep[v]) { c=u;u=v;v=c;}
            updata(id[son[u]],id[v],1,1,n,x);
        }
    }
	static void updata(int a,int b,int k,int l,int r,int x)
	{
		if(a>r||b<l) return;
		if(a<=l&&r<=b)
		{
			sum[k]=1;
			mm[k]=x;
			ll[k]=rr[k]=x;
		}
		else
		{
			int mid=(l+r)/2;
			pushdown(k);
			updata(a,b,k*2,l,mid,x);
			updata(a,b,k*2+1,mid+1,r,x);
			pushup(k);
		}
	}
	static void pushdown(int k)
	{
		if(mm[k]==-1) return;
		mm[k*2]=mm[k*2+1]=mm[k];
		ll[k*2]=ll[k*2+1]=mm[k];
		rr[k*2]=rr[k*2+1]=mm[k];
		sum[k*2]=sum[k*2+1]=1;
		mm[k]=-1;
	}
	static void pushup(int k)
	{
		sum[k]=sum[k*2]+sum[k*2+1];
		if(rr[k*2]==ll[k*2+1]) sum[k]--;
		ll[k]=ll[k*2];
		rr[k]=rr[k*2+1];
	}
	static int get(int a,int k,int l,int r)
	{
		if(l==r) return mm[k];
		int mid=(l+r)/2;
		pushdown(k);
		if(a<=mid) return get(a,k*2,l,mid);
		return get(a,k*2+1,mid+1,r);
	}
	static int sum(int a,int b,int k,int l,int r)
	{
		if(a>r||b<l) return 0;
		if(a<=l&&r<=b) return sum[k];
		int mid=(l+r)/2,res=0;
		pushdown(k);
		res+=sum(a,b,k*2,l,mid);
		res+=sum(a,b,k*2+1,mid+1,r);
		if(mid>=a&&mid<b&&rr[k*2]==ll[k*2+1])
			res--;
		return res;
	}

	public static void main(String[] args) throws IOException {
		while(in.nextToken()!=StreamTokenizer.TT_EOF)
		{
			n=(int)in.nval;m=nextInt();
			Arrays.fill(head,-1);ee=0;
			for(int i=1;i<n;i++)
			{
				a=nextInt();b=nextInt();
				c=nextInt();
				add(a,b,c);add(b,a,c);
			}
			prepare();
			while(m-->0)
			{
				op=next().charAt(0);
				a=nextInt();b=nextInt();
				if(op=='Q')
					out.println(Query(a,b));
				else
				{
					c=nextInt();
					Change(a,b,c);
				}
			}
			out.flush();
		}
		out.flush();
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值