List wants to travel
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 331 Accepted Submission(s): 66
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
【题意】一颗无根树,两种操作:改变路径上的颜色,和询问路径上有多少段颜色。
【解题方法】算是bzoj原题了。。。bzoj 2243,不过bzoj上是点权,这里是边权,改一下就可以A了。这题之前写过,当时参考了这篇blog:http://blog.csdn.net/viphong/article/details/52167628
【具体分析】
原题是 点权,那么只需要查询时,判断当前链的顶端与链子的顶端的父亲是否同色即可。(或者判断链子的末端与last链的top是否同色),而现在是边权,则我们分开判断lca(u,v)对应的两条链即可即 。 int lastu=-1,col,lastv=-1;对于 查询一条 f1到u的链,求u的颜色 col=query_col(1,1,pos,p[u]);if (col==lastu) tmp--;最后u和v在一条链时,分别判断 u和lastu,v和lastv是否相等 (if u==v只判断一次即可)
【AC 代码】
//
//Created by just_sort 2016/9/12 17:37
//Copyright (c) 2016 just_sort.All Rights Reserved
//
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 100050;
struct Edge
{
int to,next,w;
Edge(){}
Edge(int a,int b,int c){to=a,next=b,w=c;}
}edge[maxn*2],tmp[maxn];
int head[maxn],tot,n,m,top[maxn],fa[maxn],dep[maxn],num[maxn],tid[maxn],son[maxn],tim;
void init(){
tot = tim = 0;
memset(head,-1,sizeof(head));
memset(son,-1,sizeof(son));
}
void addedge(int u,int v,int w){
edge[tot]={v,head[u],w};
head[u] = tot++;
}
void dfs1(int u,int pre,int d)
{
dep[u] = d;
fa[u] = pre;
num[u] = 1;
for(int i = head[u]; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v != pre)
{
dfs1(v,u,d+1);
num[u] += num[v];
if(son[u] == -1 || num[v] > num[son[u]])
son[u] = v;
}
}
}
void dfs2(int u,int tp)
{
top[u] = tp;
tid[u] = ++tim;
if(son[u]!=-1)
dfs2(son[u],tp);
for(int i = head[u] ; i != -1; i = edge[i].next)
{
int v = edge[i].to;
if(v != son[u] && v != fa[u])
dfs2(v,v);
}
}
struct SegmentTree
{
int sum[4*maxn],add[4*maxn], numl[maxn*4], numr[maxn*4];
void init()
{
memset(sum,0,sizeof sum);
memset(add,0,sizeof add);
memset(numl,0,sizeof numl);
memset(numr,0,sizeof numr);
}
void build(int l,int r,int rt)
{
add[rt] = -1;
sum[rt] = 0;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
void pushUp(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1]-(numr[rt<<1]==numl[rt<<1|1]);
numl[rt]=numl[rt<<1];
numr[rt]=numr[rt<<1|1];
}
void pushDown(int rt, int l, int r)
{
if(add[rt] != -1)
{
add[rt<<1]=add[rt<<1|1]=add[rt];
numl[rt<<1]=numl[rt<<1|1]=add[rt];
numr[rt<<1]=numr[rt<<1|1]=add[rt];
sum[rt<<1]=sum[rt<<1|1]=1;
add[rt]=-1;
}
}
void update(int rt, int l, int r, int L,int R, int c)
{
if(l > R || L > r)
return ;
if(l >=L && r <=R )
{
sum[rt]=1;
add[rt]=numl[rt]=numr[rt]=c;
return ;
}
pushDown(rt, l, r);
int mid = (l + r) >> 1;
update(rt << 1, l, mid, L,R, c);
update(rt << 1 | 1, mid + 1, r, L,R, c);
pushUp(rt);
}
int query(int rt, int l, int r, int L, int R)
{
if(l > R || L > r)
return 0;
if(l >= L && r <= R)
return sum[rt];
pushDown(rt, l, r);
int m=(l+r)/2;
int ret=0;
if(L<=m) ret+=query(rt<<1,l,m,L,R);
if(m<R) ret+=query(rt<<1|1,m+1,r,L,R);
if(L<=m&&m<R) ret-=(numr[rt<<1]==numl[rt<<1|1]);
return ret;
}
int querycol(int rt, int l, int r, int x)
{
if(l==r) return add[rt];
pushDown(rt, l, r);
int m=(l+r)/2;
if(x<=m) return querycol(rt<<1,l,m,x);
return querycol(rt<<1|1,m+1,r,x);
}
int queryans(int u,int v)
{
int f1=top[u],f2=top[v];
int tmp=0;
int cur;
int lastu=-1,lastv=-1;
while(f1!=f2)
{
if (dep[f1]<dep[f2]){
swap(f1,f2);
swap(u,v);
swap(lastu,lastv);
}
tmp+=query(1,1,tim,tid[f1],tid[u]);
cur=querycol(1,1,tim,tid[u]);
if (cur==lastu) tmp--;
lastu=querycol(1,1,tim,tid[f1]);
u=fa[f1],f1=top[u];
}
if (u!=v)
{
if (dep[u]>dep[v] ) swap(u,v),swap(lastu,lastv);
tmp+=query(1,1,tim,tid[son[u]],tid[v]);
cur=querycol(1,1,tim,tid[v]);
if (cur==lastv) tmp--;
cur=querycol(1,1,tim,tid[son[u]]);
if (cur==lastu) tmp--;
}
else if (lastu==lastv) tmp--;
return tmp;
}
void negnate(int u,int v,int c)
{
int f1=top[u],f2=top[v];
while(f1!=f2)
{
if (dep[f1]<dep[f2])
{
swap(f1,f2);
swap(u,v);
}
update(1,1,tim,tid[f1],tid[u],c);
u=fa[f1],f1=top[u];
}
if (dep[u]>dep[v] ) swap(u,v);
if (u!=v)
update(1,1,tim,tid[son[u]],tid[v],c);
}
}tree;
int main()
{
int u,v,w;
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
tree.init();
for (int i=1; i<n; i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
addedge(v,u,w);
tmp[i]=Edge(u,v,w);
}
dfs1(1,0,0);
dfs2(1,1);
tree.build(1,tim,1);
for (int i=1; i<n; i++)
{
u=tmp[i].next,v=tmp[i].to,w=tmp[i].w;
if (fa[u]==v) tree.update(1,1,tim,tid[u],tid[u],w);
else tree.update(1,1,tim,tid[v],tid[v],w);
}
char op[10];
for (int i=1; i<=m; i++)
{
scanf("%s%d%d",op,&u,&v);
if (op[0]=='Q'){
if(u==v) printf("0\n");
else printf("%d\n",tree.queryans(u,v));
}
else{
scanf("%d",&w);
tree.negnate(u,v,w);
}
}
}
return 0;
}