[SDOI2014]旅行解题报告
题目描述
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]旅行解题报告的更多相关文章
- 洛谷 P3313 [SDOI2014]旅行 解题报告
P3313 [SDOI2014]旅行 题目描述 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教 ...
- 洛谷 P3312 [SDOI2014]数表 解题报告
P3312 [SDOI2014]数表 题目描述 有一张\(N*M\)的数表,其第\(i\)行第\(j\)列(\(1\le i \le n\),\(1 \le j \le m\))的数值为能同时整除\( ...
- hdu 2066 一个人的旅行 解题报告
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2066 题目意思:给出T条路,和草儿家相邻的城市编号,以及草儿想去的地方的编号.问从草儿家到达草儿想去的 ...
- BZOJ 3531: [Sdoi2014]旅行 [树链剖分]
3531: [Sdoi2014]旅行 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 1685 Solved: 751[Submit][Status] ...
- CH Round #56 - 国庆节欢乐赛解题报告
最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...
- 二模13day1解题报告
二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...
- BZOJ 1051 最受欢迎的牛 解题报告
题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4438 Solved: 2353[S ...
- 习题:codevs 2822 爱在心中 解题报告
这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...
- 习题:codevs 1035 火车停留解题报告
本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...
随机推荐
- python有哪些比较隐藏的知识点?
一.复用小整数以及小字符串 在Python语言中,设计者在优化Python语言时,为了提高Python的运行效率,所以就将一些小整数保存在系统表,没有释放回收(正常情况下,当Python中一个对象没有 ...
- P2051 中国象棋
P2051 中国象棋 题目描述 这次小可可想解决的难题和中国象棋有关,在一个N行M列的棋盘上,让你放若干个炮(可以是0个),使得没有一个炮可以攻击到另一个炮,请问有多少种放置方法.大家肯定很清楚,在中 ...
- 手动启动 oracle 服务
手动启动 Oracle 服务 为了学习,我们常常会在个人PC上安装 Oracle 数据库,这大大影响了计算机的运行速度,尤其是计算机开机速度,如果 Oracle 使用频率并不是非常高,我们可以禁止 ...
- SpringBoot 整合 中国移动 MAS HTTP1.0 实现短信发送服务
因为客户需要,本身使用的 阿里云的短信服务改为了中国移动MAS HTTP 1.0 短信通知,因为看到网络上关于此类的博客知识很少,再趟完坑后特地写下这篇博客,提醒后来人. 特别感谢 中国移动MAS ...
- Fleury算法
关于为什么不选桥 因为选桥之后会变成两个联通分支,这时由于可能产生的新联通分支不是孤立顶点,他俩都不联通了,那么也就绝对不可能“一笔画”走下来了 关于为什么可以选除桥之外的任意一条边走 本质原因是因为 ...
- poj3207 Ikki's Story IV - Panda's Trick 2-SAT
题目传送门 题意:在一个圆上顺时针安放着n个点,给出m条线段连接端点,要求线段不相交,线段可以在圆内也可以在圆外,问是否可以. 思路:假设一条线段,放在圆外是A,放在园内是A',那么两条线段如果必须一 ...
- 蓝桥杯-Anagrams问题
算法训练 Anagrams问题 时间限制:1.0s 内存限制:512.0MB 问题描述 Anagrams指的是具有如下特性的两个单词:在这两个单词当中,每一个英文字母(不区分大小写 ...
- 角色用户权限RBAC
关于角色.用户.权限的表设计,已经成为经典中的经典,到处都在用,这里只是收录一下: 角色表:{role_id,role_name} 用户表:{user_id,user_name} 权限表:{permi ...
- Map集合的四种遍历方式(转载)
import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class TestMap { pu ...
- jQuery事件之传递参数
一.jQuery绑定事件的三种方法 我们这里首先复习一下jQuery绑定事件的三种方法: target.click(function(){}); target.on("click" ...