题目描述

S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。

为了方便,我们用不同的正整数代表各种宗教, S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。

在S国的历史上常会发生以下几种事件:

“CC x c“:城市x的居民全体改信了c教;

“CW x w“:城市x的评级调整为w;

“QS x y“:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;

“QM x y“:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级最大值。

由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。

                    --by luogu

http://daniu.luogu.org/problem/show?pid=3313



得到模型——询问树上两点间路径中符合条件的点的加和与最值,支持单点修改权值和条件;

考虑建立C(宗教数)棵线段树——然后内存显然不够,

但可以不把她们开满:

如对于宗教i所属的线段树,只有属于宗教i的叶节点以及其祖先结构被建立;

相当于每个叶节点连一条向相应根的树链;

于是c棵线段树等价于n-条树链;

nlogn级内存;

对于每次宗教修改:

把原树上该点的权值清零,在该点的新宗教的树中建一条通向她的树链,为了方便下次修改,记得把原数组中的宗教值修改;

对于每次权值修改:

直接修改即可;

一个优化:

每次修改时动态的把已经为零的树链断开;

这样貌似可以减小查询的常数(因为当查询到不存在的树链时会直接返回)

然而实际评测时发现仿佛没什么用

代码如下:(精简而合适的代码)

 #include<cstdio>
#include<cstring>
const int MAXN=;
int n,m,L,R;
int reli[MAXN],dis[MAXN],dep[MAXN],size[MAXN],fa[MAXN],hine[MAXN],rank[MAXN],top[MAXN],a[MAXN];
struct pool{
int sum,ls,rs,max;
}data[MAXN*];
int tot;
int root[MAXN];
struct ss{
int next,to;
}e[MAXN<<];
int first[MAXN],num;
void swap(int& a,int& b){int i=a;a=b;b=i;}
void Init();
void build(int ,int );
void dfs_1(int );
void dfs_2(int ,int );
void work();
void chan_reli(int ,int );
void chan_sum(int ,int );
void get(int ,int ,int );
void up(int );
void builine(int ,int ,int&,int ,int );
int g_sum(int ,int ,int );
int g_max(int ,int ,int );
int main()
{
Init();
work();
return ;
}
void Init(){
int i,j,k;
memset(dep,,sizeof(dep));
memset(size,,sizeof(size));
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
scanf("%d%d",&dis[i],&reli[i]);
for(i=;i<n;i++){
hine[i]=i;
scanf("%d%d",&j,&k);
build(j,k);build(k,j);
}
hine[n]=n;dep[]=;
dfs_1();num=;
dfs_2(,);num=;
for(i=;i<=n;i++)
builine(,n,root[reli[a[i]]],i,dis[a[i]]);
}
void build(int f,int t){
e[++num].next=first[f];
e[num].to=t;
first[f]=num;
}
void dfs_1(int now){
int i;
for(i=first[now];i;i=e[i].next)
if(!dep[e[i].to]){
dep[e[i].to]=dep[now]+;
fa[e[i].to]=now;
dfs_1(e[i].to);
size[now]+=size[e[i].to];
if(hine[now]==now||size[e[i].to]>size[hine[now]])
hine[now]=e[i].to;
}
size[now]++;
}
void dfs_2(int now,int now_top){
int i;
top[now]=now_top;
rank[now]=++num;
a[num]=now;
if(hine[now]!=now)
dfs_2(hine[now],now_top);
for(i=first[now];i;i=e[i].next)
if(dep[e[i].to]==dep[now]+&&e[i].to!=hine[now])
dfs_2(e[i].to,e[i].to);
}
void work(){
int i,j,k,u,v;
char s[];
for(i=;i<=m;i++){
scanf("%s%d%d",s,&u,&v);
switch(s[]){
case 'C':chan_reli(u,v);break;
case 'W':chan_sum(u,v);break;
case 'S':get(u,v,);break;
case 'M':get(u,v,);break;
}
}
}
void chan_reli(int u,int v){
builine(,n,root[v],rank[u],dis[u]);
builine(,n,root[reli[u]],rank[u],);
reli[u]=v;
}
void chan_sum(int u,int v){
builine(,n,root[reli[u]],rank[u],v);
dis[u]=v;
}
void get(int u,int v,int kind){
int ans=,ro=root[reli[u]],i,j,k;
while(top[u]!=top[v]){
if(dep[top[u]]>dep[top[v]]){
L=rank[top[u]];R=rank[u];
u=fa[top[u]];
}
else{
L=rank[top[v]];R=rank[v];
v=fa[top[v]];
}
if(!kind)
ans+=g_sum(,n,ro);
else{
i=g_max(,n,ro);
if(i>ans)ans=i;
}
}
if(dep[u]>dep[v]){
swap(u,v);
}
L=rank[u];R=rank[v];
if(!kind)
ans+=g_sum(,n,ro);
else{
i=g_max(,n,ro);
if(i>ans)ans=i;
}
printf("%d\n",ans);
}
void up(int nu){
data[nu].sum=data[data[nu].ls].sum+data[data[nu].rs].sum;
data[nu].max=data[data[nu].ls].max>data[data[nu].rs].max?data[data[nu].ls].max:data[data[nu].rs].max;
}
void builine(int l,int r,int&now,int x,int sum){
if(!now){
now=++tot;
}
if(l==r){
data[now].sum=sum;
data[now].max=sum;
return ;
}
int mid=(l+r)>>;
if(x<=mid)
builine(l,mid,data[now].ls,x,sum);
else
builine(mid+,r,data[now].rs,x,sum);
up(now);
if(!data[now].sum)now=;
}
int g_sum(int l,int r,int now){
if(!now)
return ;
if(L<=l&&r<=R)
return data[now].sum;
int mid=(l+r)>>,ans=;
if(L<=mid)
ans+=g_sum(l,mid,data[now].ls);
if(R>mid)
ans+=g_sum(mid+,r,data[now].rs);
return ans;
}
int g_max(int l,int r,int now){
if(!now)
return ;
if(L<=l&&r<=R)
return data[now].max;
int mid=(l+r)>>,lm=,rm=;
if(L<=mid)
lm=g_max(l,mid,data[now].ls);
if(R>mid)
rm=g_max(mid+,r,data[now].rs);
if(lm>=rm)
return lm;
return rm;
}

祝AC

[SDOI2014]旅行解题报告的更多相关文章

  1. 洛谷 P3313 [SDOI2014]旅行 解题报告

    P3313 [SDOI2014]旅行 题目描述 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教 ...

  2. 洛谷 P3312 [SDOI2014]数表 解题报告

    P3312 [SDOI2014]数表 题目描述 有一张\(N*M\)的数表,其第\(i\)行第\(j\)列(\(1\le i \le n\),\(1 \le j \le m\))的数值为能同时整除\( ...

  3. hdu 2066 一个人的旅行 解题报告

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2066 题目意思:给出T条路,和草儿家相邻的城市编号,以及草儿想去的地方的编号.问从草儿家到达草儿想去的 ...

  4. BZOJ 3531: [Sdoi2014]旅行 [树链剖分]

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1685  Solved: 751[Submit][Status] ...

  5. CH Round #56 - 国庆节欢乐赛解题报告

    最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...

  6. 二模13day1解题报告

    二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...

  7. BZOJ 1051 最受欢迎的牛 解题报告

    题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4438  Solved: 2353[S ...

  8. 习题:codevs 2822 爱在心中 解题报告

    这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...

  9. 习题:codevs 1035 火车停留解题报告

    本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...

随机推荐

  1. python有哪些比较隐藏的知识点?

    一.复用小整数以及小字符串 在Python语言中,设计者在优化Python语言时,为了提高Python的运行效率,所以就将一些小整数保存在系统表,没有释放回收(正常情况下,当Python中一个对象没有 ...

  2. P2051 中国象棋

    P2051 中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中 ...

  3. 手动启动 oracle 服务

      手动启动 Oracle 服务 为了学习,我们常常会在个人PC上安装 Oracle 数据库,这大大影响了计算机的运行速度,尤其是计算机开机速度,如果 Oracle 使用频率并不是非常高,我们可以禁止 ...

  4. SpringBoot 整合 中国移动 MAS HTTP1.0 实现短信发送服务

    因为客户需要,本身使用的 阿里云的短信服务改为了中国移动MAS HTTP 1.0  短信通知,因为看到网络上关于此类的博客知识很少,再趟完坑后特地写下这篇博客,提醒后来人. 特别感谢 中国移动MAS ...

  5. Fleury算法

    关于为什么不选桥 因为选桥之后会变成两个联通分支,这时由于可能产生的新联通分支不是孤立顶点,他俩都不联通了,那么也就绝对不可能“一笔画”走下来了 关于为什么可以选除桥之外的任意一条边走 本质原因是因为 ...

  6. poj3207 Ikki's Story IV - Panda's Trick 2-SAT

    题目传送门 题意:在一个圆上顺时针安放着n个点,给出m条线段连接端点,要求线段不相交,线段可以在圆内也可以在圆外,问是否可以. 思路:假设一条线段,放在圆外是A,放在园内是A',那么两条线段如果必须一 ...

  7. 蓝桥杯-Anagrams问题

     算法训练 Anagrams问题   时间限制:1.0s   内存限制:512.0MB      问题描述 Anagrams指的是具有如下特性的两个单词:在这两个单词当中,每一个英文字母(不区分大小写 ...

  8. 角色用户权限RBAC

    关于角色.用户.权限的表设计,已经成为经典中的经典,到处都在用,这里只是收录一下: 角色表:{role_id,role_name} 用户表:{user_id,user_name} 权限表:{permi ...

  9. Map集合的四种遍历方式(转载)

    import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class TestMap { pu ...

  10. jQuery事件之传递参数

    一.jQuery绑定事件的三种方法 我们这里首先复习一下jQuery绑定事件的三种方法: target.click(function(){}); target.on("click" ...