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();
}
}