3083: 遥远的国度

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 4859  Solved: 1372
[Submit][Status][Discuss]

Description

描述
zcwwzdjn在追杀十分sb的zhx,而zhx逃入了一个遥远的国度。当zcwwzdjn准备进入遥远的国度继续追杀时,守护神RapiD阻拦了zcwwzdjn的去路,他需要zcwwzdjn完成任务后才能进入遥远的国度继续追杀。

问题是这样的:遥远的国度有n个城市,这些城市之间由一些路连接且这些城市构成了一颗树。这个国度有一个首都,我们可以把这个首都看做整棵树的根,但遥远的国度比较奇怪,首都是随时有可能变为另外一个城市的。遥远的国度的每个城市有一个防御值,有些时候RapiD会使得某两个城市之间的路径上的所有城市的防御值都变为某个值。RapiD想知道在某个时候,如果把首都看做整棵树的根的话,那么以某个城市为根的子树的所有城市的防御值最小是多少。由于RapiD无法解决这个问题,所以他拦住了zcwwzdjn希望他能帮忙。但zcwwzdjn还要追杀sb的zhx,所以这个重大的问题就被转交到了你的手上。

Input

第1行两个整数n m,代表城市个数和操作数。
第2行至第n行,每行两个整数 u v,代表城市u和城市v之间有一条路。
第n+1行,有n个整数,代表所有点的初始防御值。
第n+2行一个整数 id,代表初始的首都为id。
第n+3行至第n+m+2行,首先有一个整数opt,如果opt=1,接下来有一个整数id,代表把首都修改为id;如果opt=2,接下来有三个整数p1
p2 v,代表将p1 p2路径上的所有城市的防御值修改为v;如果opt=3,接下来有一个整数
id,代表询问以城市id为根的子树中的最小防御值。

Output

对于每个opt=3的操作,输出一行代表对应子树的最小点权值。

Sample Input

3 7
1 2
1 3
1 2 3
1
3 1
2 1 1 6
3 1
2 2 2 5
3 1
2 3 3 4
3 1

Sample Output

1
2
3
4
提示
对于20%的数据,n<=1000 m<=1000。
对于另外10%的数据,n<=100000,m<=100000,保证修改为单点修改。
对于另外10%的数据,n<=100000,m<=100000,保证树为一条链。
对于另外10%的数据,n<=100000,m<=100000,没有修改首都的操作。
对于100%的数据,n<=100000,m<=100000,0<所有权值<=2^31。

HINT

Source

zhonghaoxi提供

题解

我也是有B站账号的女人了!

这道题除了换根以外就很板子了,——所以我们聊聊换根。

首先在原根下建出一棵树,设当前的根为root。
对于子树k的操作:
1.root==k 那么对整棵树操作。
2.lca(root,k)!=k 也就是说root对k并没有什么影响,直接操作k。
3.lca(root,k)==k root在k的子树中,想象一下揪着一根毛拿起一顶假发......
那么对整个树中,除了原根意义下 k的儿子中含root的那一股 以外,的整棵树操作。
(也可以认为对整个树操作,然后对root那一股撤销操作

其实,所谓的换根操作,并不是要你每次把树再重新建一遍(复杂度起飞

而是考你分类讨论的能力QAQ

——

然后,一定一定要注意边界啊!字母不要混用啊!QAQ

以及 鉴于数据极接近maxint,不如直接longlong2333

 /**************************************************************
Problem: 3083
User: qwerta
Language: C++
Result: Accepted
Time:5528 ms
Memory:55532 kb
****************************************************************/ #include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define R register
const int MAXN=;
struct emm{
int e,f;
}b[*MAXN];
int h[MAXN];
int tot=;
void con(int u,int v)
{
b[++tot].f=h[u];
h[u]=tot;
b[tot].e=v;
b[++tot].f=h[v];
h[v]=tot;
b[tot].e=u;
return;
}
int d[MAXN],fa[MAXN],top[MAXN],siz[MAXN],z[MAXN];
void dfs(int x)
{
siz[x]=,top[x]=x;
int mac=,macc=-;
for(R int i=h[x];i;i=b[i].f)
if(!d[b[i].e])
{
d[b[i].e]=d[x]+;
fa[b[i].e]=x;
dfs(b[i].e);
siz[x]+=siz[b[i].e];
if(macc<siz[b[i].e]){mac=b[i].e,macc=siz[b[i].e];}
}
z[x]=mac;
top[mac]=x;
return;
}
int q[MAXN],dfn[MAXN];
void dfss(int x)
{
q[++tot]=x;
dfn[x]=tot;
if(z[x])dfss(z[x]);
for(R int i=h[x];i;i=b[i].f)
if(d[b[i].e]==d[x]+&&b[i].e!=z[x])
dfss(b[i].e);
return;
}
int val[MAXN];
int fitop(int x)
{
if(top[x]==x)return x;
return top[x]=fitop(top[x]);
}
struct ahh{
int l,r,mid;
long long v,laz;
}a[*MAXN];
#define lz (i<<1)
#define rz ((i<<1)|1)
#define md a[i].mid
void build(int i,int ll,int rr)
{
a[i].l=ll;
a[i].r=rr;
if(ll==rr){a[i].v=val[q[ll]];return;}
md=(ll+rr)>>;
build(lz,ll,md);
build(rz,md+,rr);
a[i].v=min(a[lz].v,a[rz].v);
return;
}
int k;
void pushtag(int i)//啰嗦的pushtag
{
if(!a[i].laz)return;
a[i].v=a[i].laz;
if(a[i].l!=a[i].r)
{
a[lz].v=a[lz].laz=a[i].laz;
a[rz].v=a[rz].laz=a[i].laz;
}
a[i].laz=;
return;
}
void change(int i,int ll,int rr)
{
pushtag(i);//覆盖操作可不像累加有交换律啊!修改也要pushtagQAQ
if(a[i].l==ll&&a[i].r==rr){a[i].v=a[i].laz=k;return;}
if(rr<=md)change(lz,ll,rr);
else if(md+<=ll)change(rz,ll,rr);
else {change(lz,ll,md);change(rz,md+,rr);}
a[i].v=min(a[lz].v,a[rz].v);//记得一路更新上去QAQ
return;
}
long long ans;
void find(int i,int ll,int rr)
{
pushtag(i);
if(a[i].l==ll&&a[i].r==rr){ans=min(ans,a[i].v);return;}
if(rr<=md)find(lz,ll,rr);
else if(md+<=ll)find(rz,ll,rr);
else {find(lz,ll,md);find(rz,md+,rr);}
a[i].v=min(a[lz].v,a[rz].v);
return;
}
int filca(int u,int v)
{
while(top[u]!=top[v])
{
if(d[top[u]]<d[top[v]])swap(u,v);
u=fa[top[u]];
}
if(d[u]<d[v])swap(u,v);
return v;
}
int main()
{
//freopen("a.in","r",stdin);
int n,m;
scanf("%d%d",&n,&m);
for(R int i=;i<n;++i)
{
int u,v;
scanf("%d%d",&u,&v);
con(u,v);
}
for(R int i=;i<=n;++i)
scanf("%d",&val[i]);
int s;
scanf("%d",&s);
d[s]=;
dfs(s);
tot=;
dfss(s);
for(R int i=;i<=n;++i)
top[i]=fitop(i);
build(,,n);
int rot=s;
for(R int ew=;ew<=m;++ew)//顺手打i->疯狂WA
{
int opt;
scanf("%d",&opt);
if(opt==)
{
int id;
scanf("%d",&id);
rot=id;
}
else if(opt==)
{
int u,v;
scanf("%d%d%d",&u,&v,&k);
while(top[u]!=top[v])
{
if(d[top[u]]<d[top[v]])swap(u,v);
change(,dfn[top[u]],dfn[u]);
u=fa[top[u]];
}
if(d[u]<d[v])swap(u,v);
change(,dfn[v],dfn[u]);
}
else
{
int x;
scanf("%d",&x);
ans=;
if(rot==x)
find(,dfn[s],dfn[s]+siz[s]-);
else
{
int lca=filca(rot,x);
if(lca!=x)
find(,dfn[x],dfn[x]+siz[x]-);
else
{
for(R int i=h[x];i;i=b[i].f)
if(d[b[i].e]==d[x]+)
{
if(dfn[b[i].e]<=dfn[rot]&&dfn[b[i].e]+siz[b[i].e]->=dfn[rot])
{
find(,,dfn[b[i].e]-);
if(dfn[b[i].e]+siz[b[i].e]<=n)//不注意边界->疯狂RE
find(,dfn[b[i].e]+siz[b[i].e],n);
}
}
}
}
printf("%lld\n",ans);
}
}
return ;
}

把AC率丢到地上蹂躏.jpg

「BZOJ3083」遥远的国度(树剖换根的更多相关文章

  1. Loj #2570. 「ZJOI2017」线段树

    Loj #2570. 「ZJOI2017」线段树 题目描述 线段树是九条可怜很喜欢的一个数据结构,它拥有着简单的结构.优秀的复杂度与强大的功能,因此可怜曾经花了很长时间研究线段树的一些性质. 最近可怜 ...

  2. P3979 遥远的国度 树剖

    P3979 遥远的国度 树剖 题面 需要想一下的树剖题,对于询问三需要处理换跟后的情况.我们以1为树根跑一遍剖分,对于换跟进行分类讨论,算出实际答案.讨论有三种情况: (以1为树根的树上) 跟在询问节 ...

  3. 「ZJOI2019」线段树 解题报告

    「ZJOI2019」线段树 听说有人喷这个题简单,然后我就跑去做,然后自闭感++,rp++(雾) 理性分析一波,可以发现最后形成的\(2^k\)个线段树,对应的操作的一个子集,按时间顺序作用到这颗线段 ...

  4. 「JSOI2015」字符串树

    「JSOI2015」字符串树 传送门 显然可以树上差分. 我们对于树上每一条从根出发的路径都开一 棵 \(\text{Trie}\) 树,那么我们就只需要在 \(\text{Trie}\) 树中插入一 ...

  5. 「SHOI2014」三叉神经树 解题报告

    「SHOI2014」三叉神经树 膜拜神仙思路 我们想做一个类似于动态dp的东西,首先得确保我们的运算有一个交换律,这样我们可以把一长串的运算转换成一块一块的放到矩阵上之类的东西,然后拿数据结构维护. ...

  6. 「模板」 线段树——区间乘 && 区间加 && 区间求和

    「模板」 线段树--区间乘 && 区间加 && 区间求和 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long l ...

  7. 【LOJ】#3043. 「ZJOI2019」线段树

    LOJ#3043. 「ZJOI2019」线段树 计数转期望的一道好题-- 每个点设两个变量\(p,q\)表示这个点有\(p\)的概率有标记,有\(q\)的概率到祖先的路径上有个标记 被覆盖的点$0.5 ...

  8. 【LOJ】#2983. 「WC2019」数树

    LOJ2983. 「WC2019」数树 task0 有\(i\)条边一样答案就是\(y^{n - i}\) task1 这里有个避免容斥的方法,如果有\(i\)条边重复我们要算的是\(y^{n - i ...

  9. 「SHOI2014」三叉神经树

    「SHOI2014」三叉神经树 给你一颗由\(n\)个非叶子结点和\(2n+1\)个叶子结点构成的完全三叉树,每个叶子结点有一个输出:\(0\)或\(1\),每个非叶子结点的输出为自己的叶子结点中较多 ...

随机推荐

  1. Mac环境下安装运行splash

    http://blog.csdn.net/chenhy8208/article/details/69391097 最近需要使用scrapy爬虫做一些开发,用到了splash.我本机是mac环境,跳着看 ...

  2. 【翻译自mos文章】检查$ORACLE_HOME是否是RAC的HOME的方法以及relink RAC的Oracle binary的方法

    检查$ORACLE_HOME是否是RAC的HOME的方法以及relink RAC的Oracle binary的方法 来源于: How to Check Whether Oracle Binary/In ...

  3. java设计模式之-建造者模式

    建造者模式可以将复杂的构建与其表示相分离,是的相同的构建过程可以创建出不同的表示.     建造者模式与抽象工厂的差别是:在建造者模式里,有个指导者,这个指导者来管理建造者.用户与指导者相互联系,指导 ...

  4. Unity开发规范(个人习惯,仅供參考)

    近期整理了一下unity里的文件夹使用和脚本上的一些规范,这个看个人习惯,仅供參考 1.unity中的Project文件夹      总体文件夹大致例如以下:            按资源种类分目录. ...

  5. iOS_7_scrollView大图缩放

    终于效果图: BeyondViewController.h // // BeyondViewController.h // 7_scrollView大图展示 // // Created by beyo ...

  6. meta标签多种用法

    <meta name=”google” content=”notranslate” /> <!-- 有时,Google在结果页面会提供一个翻译链接,但有时候你不希望出现这个链接,你可 ...

  7. YAML 对中文的处理

    from yaml import load,dump f = open('xx.ymal',encoding='utf-8') l = load(f) print(f) w = open('xx_co ...

  8. 后端程序员看前端想死(三)是不是该学点js了

    CSS盒子模型 div布局 js 这些都懂一点,但仅仅是懂一点,有时间就学一下咯

  9. oracle数据库 操作clob对象

    clob类型,但对于这个类型处理起来还是比较麻烦的,varchar2长度为4000bytes,如果varchar2能满足楼主的需求,建议使用varchar2,下面提供了在Java 中读取clob类型的 ...

  10. (Vue)vue模板语法

    Vue.js 使用了基于 HTML 的模版语法,允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据.Vue.js 的核心是一个允许你采用简洁的模板语法来声明式的将数据渲染进 DOM 的系统. ...