题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3531

题意概述:
  给出一棵N个点的树,树上的每个结点有一个颜色和权值,支持以下四种操作:
  1.将点x的颜色改成c。
  2.将点x的权值给成w。
  3.询问x->y路径上和端点相同颜色的点的权值总和(端点颜色相同)。
  4.询问x->y路径上和端点相同颜色的点的权值最大值(端点颜色相同)。

分析:

  首先树链剖分,每条链开C棵维护每个颜色的线段树。动态开点。

  感觉没什么好说的......考试的时候灵光一闪就来了......之前还在YYlct之类的......

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
using namespace std;
const int maxn=;
const int SIZE=; int N,Q,C[maxn],W[maxn];
map<int,int>rt[maxn];
struct edge{ int to,next; }E[maxn<<];
int first[maxn],np,dep[maxn],top[maxn],fa[maxn],son[maxn],sz[maxn],len[maxn];
int lc[SIZE],rc[SIZE],sum[SIZE],mx[SIZE],np2; void _scanf(int &x)
{
x=;
char ch=getchar();
while(ch<''||ch>'') ch=getchar();
while(ch>=''&&ch<='') x=x*+ch-'',ch=getchar();
}
void _scanf(char *s)
{
int cnt=;
char ch=getchar();
while(!isalpha(ch)) ch=getchar();
while(isalpha(ch)) s[cnt++]=ch,ch=getchar();
s[cnt]='\0';
}
int out_cnt,out[];
void _printf(int x)
{
out[++out_cnt]=x%,x/=;
while(x) out[++out_cnt]=x%,x/=;
while(out_cnt) putchar(''+out[out_cnt--]);
putchar('\n');
}
void add_edge(int u,int v){
E[++np]=(edge){v,first[u]};
first[u]=np;
}
void data_in()
{
_scanf(N);_scanf(Q);
for(int i=;i<=N;i++) _scanf(W[i]),_scanf(C[i]);
int x,y;
for(int i=;i<N;i++){
_scanf(x);_scanf(y);
add_edge(x,y); add_edge(y,x);
}
}
void DFS1(int i,int f,int d){
fa[i]=f,dep[i]=d,sz[i]=;
for(int p=first[i];p;p=E[p].next){
int j=E[p].to;
if(j==f) continue;
DFS1(j,i,d+);
sz[i]+=sz[j];
if(sz[j]>sz[son[i]]) son[i]=j;
}
}
void DFS2(int i,int f,int tp){
top[i]=tp,len[tp]++;
if(son[i]) DFS2(son[i],i,tp);
for(int p=first[i];p;p=E[p].next){
int j=E[p].to;
if(j==f||j==son[i]) continue;
DFS2(j,i,j);
}
}
int newnode(){
np2++,lc[np2]=rc[np2]=,sum[np2]=mx[np2]=;
return np2;
}
void pushup(int now){
mx[now]=max(mx[lc[now]],mx[rc[now]]);
sum[now]=sum[lc[now]]+sum[rc[now]];
}
void update(int &now,int L,int R,int pos,int v){
if(!now) now=newnode();
if(L==R){ sum[now]=mx[now]=v; return; }
int m=L+R>>;
if(pos<=m) update(lc[now],L,m,pos,v);
else update(rc[now],m+,R,pos,v);
pushup(now);
}
void build(int i,int f){
update(rt[top[i]][C[i]],,len[top[i]]-,dep[i]-dep[top[i]],W[i]);
for(int p=first[i];p;p=E[p].next){
if(E[p].to==f) continue;
build(E[p].to,i);
}
}
int query1(int now,int L,int R,int A,int B){
if(!now) return ;
if(A<=L&&R<=B) return sum[now];
int m=L+R>>;
if(B<=m) return query1(lc[now],L,m,A,B);
if(A>m) return query1(rc[now],m+,R,A,B);
return query1(lc[now],L,m,A,B)+query1(rc[now],m+,R,A,B);
}
int query2(int now,int L,int R,int A,int B){
if(!now) return ;
if(A<=L&&R<=B) return mx[now];
int m=L+R>>;
if(B<=m) return query2(lc[now],L,m,A,B);
if(A>m) return query2(rc[now],m+,R,A,B);
return max(query2(lc[now],L,m,A,B),query2(rc[now],m+,R,A,B));
}
int LCA(int x,int y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=fa[top[x]];
}
return dep[x]<dep[y]?x:y;
}
int query_s(int x,int y,int c){
int re=;
while(top[x]!=top[y]){
re+=query1(rt[top[x]][c],,len[top[x]]-,,dep[x]-dep[top[x]]);
x=fa[top[x]];
}
re+=query1(rt[top[x]][c],,len[top[x]]-,dep[y]-dep[top[x]],dep[x]-dep[top[x]]);
return re;
}
int query_m(int x,int y,int c){
int re=;
while(top[x]!=top[y]){
re=max(re,query2(rt[top[x]][c],,len[top[x]]-,,dep[x]-dep[top[x]]));
x=fa[top[x]];
}
re=max(re,query2(rt[top[x]][c],,len[top[x]]-,dep[y]-dep[top[x]],dep[x]-dep[top[x]]));
return re;
}
void work()
{
DFS1(,,);
DFS2(,,);
build(,);
char op[];
int x,y,z,p,c,w,ans;
for(int i=;i<=Q;i++){
_scanf(op);
if(op[]=='C'&&op[]=='C'){
_scanf(x);_scanf(c);
update(rt[top[x]][C[x]],,len[top[x]]-,dep[x]-dep[top[x]],);
update(rt[top[x]][C[x]=c],,len[top[x]]-,dep[x]-dep[top[x]],W[x]);
}
else if(op[]=='C'&&op[]=='W'){
_scanf(x);_scanf(w);
update(rt[top[x]][C[x]],,len[top[x]]-,dep[x]-dep[top[x]],W[x]=w);
}
else if(op[]=='S'){
_scanf(x);_scanf(y);
z=LCA(x,y);
_printf(query_s(x,z,C[x])+query_s(y,z,C[x])-(C[z]==C[x]?W[z]:));
}
else if(op[]=='M'){
_scanf(x);_scanf(y);
z=LCA(x,y);
_printf(max(query_m(x,z,C[x]),query_m(y,z,C[x])));
}
}
}
int main()
{
data_in();
work();
return ;
}
 

BZOJ 3531 SDOI2014 旅行 树链剖分+线段树动态开点的更多相关文章

  1. B20J_3231_[SDOI2014]旅行_树链剖分+线段树

    B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...

  2. 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点

    题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...

  3. BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )

    BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...

  4. BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)

    BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...

  5. BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)

    前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...

  6. bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)

    4196: [Noi2015]软件包管理器 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 2852  Solved: 1668[Submit][Sta ...

  7. bzoj 2157: 旅游【树链剖分+线段树】

    裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...

  8. BZOJ 3589 动态树 (树链剖分+线段树)

    前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...

  9. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  10. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

随机推荐

  1. Angularjs 数据双向绑定

    <!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...

  2. android 学习笔记 杂记1

    getIntent().getExtras().get("intent"); 这个intent是数据包装的参数. 比如: Intent intent = new Intent(th ...

  3. ListItem Updating事件监视有没有上传附件

    using System; using System.Collections.Generic; using System.Text; using Microsoft.SharePoint; using ...

  4. 课时70.id选择器和类选择器(理解)

    1.id和class的区别? id相当于人的身份证不可以重复 class相当于人的名称可以重复 1.2 一个HTML标签只能绑定一个id名称 一个HTML标签可以绑定多个class名称 2.id选择器 ...

  5. 菜鸟笔记 -- Chapter 4.7 代码注释与编码规范

    4.7 代码注释与编码规范 在程序代码中适当的添加注释可以提高程序的可读性和可维护性.好的编码规范可以使程序更易阅读和理解.下面我们将介绍几种代码注释,以及应该注意的编码规范. 4.7.1 代码注释 ...

  6. spring入门(六) spring mvc+mybatis

    1.引入依赖 <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> < ...

  7. aes 加密,解密(2)

    JavaScript加密,解密 1,此为AES加密后,转换为16进制编码 var encodePwd = function (data,key){ var keyHex = CryptoJS.enc. ...

  8. 正则表达式之——exec,match

    刚开始接触正则,发现了一件有意思的事,我想要匹配正则,这下尴尬了- -,光知道正则表达式写法,并不知道正则如何才能获取匹配值. 慢慢摸索中... 找到答案!!! 正则匹配有两种方法: 一种是match ...

  9. oracle 11g grid软件安装[20180121]

      实验环境:     系统->Redhat 6.5     Oracle软件版本->oracle 11.2.0.4.0        系统初始化     设定hosts主机名和对应IP地 ...

  10. 一次Redis 的性能测试和问题 [问题已经自己解决,见文章最后]

    [我的问题]:请教个问题,我在本机搭建linux虚拟机+redis 3.2.6,然后在本机物理机上面测试虚拟机的redis性能,如下VM配置参数做测试,redis 的性能好像不算太好,问题待排查的两点 ...