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 安装配置Mysql

    Mac下安装配置Mysql By 白熊花田(http://blog.csdn.net/whiterbear) 转载需注明出处,谢谢. 下载安装 去官网下载Community版本号的mysql安装文件. ...

  2. 【Hibernate步步为营】--核心对象+持久对象全析(三)

    上篇文章讨论了Hibernate持久对象的生命周期,在整个生命周期中一个对象会经历三个状态,三种状态的转换过程在开发过程中是可控的.并且是通过用法来控制它们的转化过程.详细的转化过程今天就来着重讨论下 ...

  3. Spring MVC传值乱码解决

    在web.xml中进行配置,加入以下代码: <!-- 乱码解决 --> <filter> <filter-name>characterEncodingFilter& ...

  4. 建立第一个Sencha Touch应用

    准备 开始开发前,请先到下面的地址下载Sencha Touch 2的包:http://www.sencha.com/products/touch/download/ .下载完解压后你会发现包里有很多文 ...

  5. javascript变量初始化位置

    变量在之前<script type="text/javascript"></script>(或引用的js文件)中初始化,可以正常访问. 运行程序:弹出123 ...

  6. who命令

    who1.c #include <stdio.h>#include <utmp.h>#include <fcntl.h>#include <unistd.h& ...

  7. 【转】Windows2008上传大文件的解决方法(iis7解决上传大容量文件)

    2008上传大文件的解决方法:http://wenku.it168.com/d_000091739.shtml 2003上传大文件的解决方法:http://tech.v01.cn/windowsxit ...

  8. Python的专有属性

  9. 关于提高沟通能力的书单zz

    上周推荐了一份关于提高写作能力的书单,这周,我们来聊聊沟通能力. 在现代社会,沟通能力变得越来越重要.人与人之间的社交渠道越来越丰富,工作中的协同合作也越来越普遍.我们要沟通的人越来越多,节奏越来越快 ...

  10. ANALYSIS AND EXPLOITATION OF A LINUX KERNEL VULNERABILITY (CVE-2016-0728)

    ANALYSIS AND EXPLOITATION OF A LINUX KERNEL VULNERABILITY (CVE-2016-0728) By Perception Point Resear ...