【51nod 2004】终结之时
题目大意
“将世界终结前最后的画面,深深刻印进死水般的心海.”
祈愿没有得到回应,雷声冲破云霄,正在祈愿的洛天依受到了极大的打击。
洛天依叹了口气,说:”看来这个世界正如我之前所说的一样,早已失去一切生机”
你沉默了下来,没有说什么话,只是静静地坐在洛天依的身旁,一同观赏这末日之景.
天空被云朵覆盖,一朵具有强大能量的云映入你们的眼帘,这是始云!是抽取世界能量的最重要的一朵云!但是洛天依明显没有破坏这朵云的斗志了,你也只好静静地观赏.
这个世界被吸取的能量从始云开始传递,通过愿银线输送到各个积雨云上,每朵积雨云即作为能量中转点,又作为能量湮灭点。如此,整片天空构成了一个巨大的能量输送网络。很巧,我们可以用图论中的有向图来描述这个网络.
我们定义始云的编号为1.
对于一朵积雨云y,如果从始云开始到这个点的所有路径都经过了点x,那么我们称x是y的支配云,x支配y,y被x支配。显然一个点的支配云可能有多个且至少有两个。
旁边的洛天依此时非常惊讶,因为她发现不同的积雨云的能量强度不一样!
洛天依用正整数来描述这个能量的强度,同时起名为湮灭能量数.
也就是说在这个云朵湮灭的能量的单位数目.
然而整个网络中的云湮灭的能量数在不断的变化中,变化的情况如下:
C 1 u w有一股能量在云朵u中湮灭了w的能量.
C 2 u w点u支配的所有云朵上都湮灭了w能量
C 3 u w支配点u的所有的云朵上都湮灭了w的能量
“最后一次求你了,为我推演一下这毁灭能量的变化吧.”
洛天依一共有四种请求:
Q 1 u 询问u支配的所有的云朵的湮灭能量数之和.
Q 2 u 询问支配u的所有的云朵的湮灭能量数权值之和.
Q 3 s x1 x2 ... xs 询问所有支配了其中任一云朵的云朵的湮灭能量数权值之和.
R k让状态回到k次变化之前.若k大于已经执行的操作数,则视为回到初始状态.
你自然不忍心拒绝洛天依,于是你打算圆满完成这个任务.
分析
支配树裸题,
先构出支配树,然后树链剖分。
经典的树链剖分操作。
注:目前我还没有打关于支配树的介绍,因为我还不是理解透彻,本月内我将会打一篇支配树的blog。
#include <cmath>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <map>
#include <bitset>
#include <set>
#include <vector>
#define clear(a) memset(a,0,sizeof(a))
const int inf=2147483647;
const int mo=1e9+7;
const int N=100005;
using namespace std;
int head[N], pre[N], dom[N], to[N*20], nt[N*20], tot,lt[N],w[N];
void link(int *h,int fr,int tt)
{
tot ++;
nt[tot] = h[fr];
to[tot] = tt;
h[fr] = tot;
}
int n, m;
void init()
{
scanf("%d%d", &n, &m);
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
int a, b;
for(int i = 1; i <= m; ++i)
{
scanf("%d%d", &a, &b);
link(head, a, b);
link(pre, b, a);
}
}
int bcj[N], semi[N], idom[N], best[N], dfn[N], id[N], fa[N], num;
int push(int v)
{
if(v == bcj[v]) return v;
int y = push(bcj[v]);
if(dfn[semi[best[bcj[v]]]] < dfn[semi[best[v]]]) best[v] = best[bcj[v]];
return bcj[v] = y;
}
void dfs(int rt)
{
dfn[rt] = ++num;
id[num] = rt;
for(int i = head[rt]; i; i = nt[i])
if(!dfn[to[i]])
{
dfs(to[i]);
fa[to[i]] = rt;
}
}
void tarjan()
{
for(int i = n, u; i >= 2; --i)
{
u = id[i];
for(int j = pre[u]; j; j = nt[j])
{
if(!dfn[to[j]]) continue;
push(to[j]);
if(dfn[semi[best[to[j]]]] < dfn[semi[u]]) semi[u] = semi[best[to[j]]];
}
link(dom, semi[u], u);
bcj[u] = fa[u];u = id[i - 1];
for(int j = dom[u]; j; j = nt[j])
{
push(to[j]);
if(semi[best[to[j]]] == u) idom[to[j]] = u;
else idom[to[j]] = best[to[j]];
}
}
for(int i = 2, u; i <= n; ++i)
{
u = id[i];
if(idom[u] != semi[u]) idom[u] = idom[idom[u]];
link(lt,idom[u],u);
}
}
int son[N],size[N],deep[N],top[N],en[N];
void dg(int x)
{
deep[x]=deep[fa[x]]+1;
size[x]=1;
for(int i=lt[x];i;i=nt[i])
{
int j=to[i];
if(j==fa[x]) continue;
fa[j]=x;
dg(j);
size[x]+=size[j];
if(size[j]>size[son[x]]) son[x]=j;
}
}
void dg1(int x)
{
id[++num]=x,dfn[x]=num;
if(!top[x]) top[x]=x;
if(son[x]) top[son[x]]=top[x],dg1(son[x]);
for(int i=lt[x];i;i=nt[i])
{
int j=to[i];
if(j==fa[x] || j==son[x]) continue;
dg1(j);
}
en[x]=num;
}
struct tree
{
long long s,la,l,r;
}tr[N*30];
int rt[N];
void newp(int v)
{
tr[++num]=tr[tr[v].l],tr[v].l=num;
tr[++num]=tr[tr[v].r],tr[v].r=num;
}
void down(int v,int l,int r,int mid)
{
if(!tr[v].la) return;
newp(v);
tr[tr[v].l].s+=tr[v].la*(mid-l+1);
tr[tr[v].r].s+=tr[v].la*(r-mid);
tr[tr[v].l].la+=tr[v].la,tr[tr[v].r].la+=tr[v].la;
tr[v].la=0;
return;
}
void put(int v,int l,int r,int x,int y,int z)
{
if(l==x && y==r)
{
tr[v].s+=z*(r-l+1),tr[v].la+=z;
return;
}
int mid=(l+r)>>1;
down(v,l,r,mid);
if(y<=mid) tr[++num]=tr[tr[v].l],tr[v].l=num,put(tr[v].l,l,mid,x,y,z);
else
if(x>mid) tr[++num]=tr[tr[v].r],tr[v].r=num,put(tr[v].r,mid+1,r,x,y,z);
else
tr[++num]=tr[tr[v].l],tr[v].l=num,tr[++num]=tr[tr[v].r],tr[v].r=num,
put(tr[v].l,l,mid,x,mid,z),put(tr[v].r,mid+1,r,mid+1,y,z);
tr[v].s=tr[tr[v].l].s+tr[tr[v].r].s;
}
long long find(int v,int l,int r,int x,int y)
{
if(l==x && y==r) return tr[v].s;
int mid=(l+r)>>1;
down(v,l,r,mid);
if(y<=mid) return find(tr[v].l,l,mid,x,y);
else
if(x>mid) return find(tr[v].r,mid+1,r,x,y);
else
return find(tr[v].l,l,mid,x,mid)+find(tr[v].r,mid+1,r,mid+1,y);
}
void up(int v,int x,int y)
{
for(;x;x=fa[top[x]]) put(v,1,n,dfn[top[x]],dfn[x],y);
}
long long up1(int v,int x)
{
long long ans=0;
for(;x;x=fa[top[x]]) ans+=find(v,1,n,dfn[top[x]],dfn[x]);
return ans;
}
int st[N];
bool cmp(int x,int y)
{
return dfn[x]<dfn[y];
}
int lca(int u,int v)
{
int f1=top[u],f2=top[v];
while(f1!=f2)
{
if(deep[f1]<deep[f2]) swap(f1,f2),swap(u,v);
u=fa[f1],f1=top[u];
}
if(deep[u]>deep[v]) swap(u,v);
return u;
}
int main()
{
init();
for(int i=1;i<=n;i++) bcj[i]=semi[i]=best[i]=i;
dfs(1),tarjan();
num=0;
clear(fa),clear(dfn),clear(id);
dg(1),dg1(1);
rt[0]=num=1;
for(int i=1;i<=n;i++) put(rt[0],1,n,dfn[i],dfn[i],w[i]);
scanf("%d",&m);
for(int x,y,t,now=0;m--;)
{
char ch=getchar();
for(;ch!='C' && ch!='Q' && ch!='R';) ch=getchar();
if(ch=='C')
{
scanf("%d%d%d",&t,&x,&y);
rt[++now]=++num,tr[rt[now]]=tr[rt[now-1]];
if(t==1) put(rt[now],1,n,dfn[x],dfn[x],y);
else
if(t==2) put(rt[now],1,n,dfn[x],en[x],y);
else up(rt[now],x,y);
}
else
if(ch=='Q')
{
scanf("%d%d",&t,&x);
if(t==1) printf("%lld\n",find(rt[now],1,n,dfn[x],en[x]));
else
if(t==2) printf("%lld\n",up1(rt[now],x));
else
{
long long sum=0;
for(int j=1;j<=x;j++) scanf("%d",&st[j]),sum+=up1(rt[now],st[j]);
sort(st+1,st+1+x,cmp);
for(int j=1;j<x;j++) sum-=up1(rt[now],lca(st[j],st[j+1]));
printf("%lld\n",sum);
}
}
else
{
scanf("%d",&t);
now=max(0,now-t);
}
}
}
【51nod 2004】终结之时的更多相关文章
- 51nod2004 终结之时 (支配树+树剖+树链的并)
link 我永远喜欢洛天依 给定一张图世末积雨云,你需要维护其支配树: 单点修改,子树修改,树链修改 子树求和,树链求和,多条树链的并集求和 撤销之前的操作 可以先用 Lengauer-Tarjan ...
- 垃圾回收GC:.Net自己主动内存管理 上(三)终结器
垃圾回收GC:.Net自己主动内存管理 上(三)终结器 垃圾回收GC:.Net自己主动内存管理 上(一)内存分配 垃圾回收GC:.Net自己主动内存管理 上(二)内存算法 垃圾回收GC:.Net自己主 ...
- 读《Effect Java中文版》
读<Effect Java中文版> 译者序 序 前言 第1章引言 1 第2章创建和销毁对象 4 第1条:考虑用静态工厂方法代替构造函数 4 第2条:使用私有构造函数强化singleto ...
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...
- 基础才是重中之重~C#中标准的IDispose模式
回到目录 IDispose模式在C++中用的很多,用来清理资源,而在C#里,资源分为托管和非托管两种,托管资源是由C#的CLR帮助我们清理的,它是通过调用对象的析构函数完成的对象释放工作,而对于非托管 ...
- 个人阅读作业——M1/M2总结
~ http://www.cnblogs.com/wx1306/p/4831950.html 在这篇博客中,我提出来一些关于软件工程的问题,但随着这一个学期的即将结束,以及我对软件开发的了解的深入,我 ...
- Java垃圾收集学习笔记
(1)除了释放不再被引用的对象,垃圾收集器还要处理 堆碎块 .请求分配新对象时可能不得不增大堆空间的大小,虽然可以使用的空闲空间是足够的,但是堆中没有没有连续的空间放得下新对象.可能会导致虚拟机产生不 ...
- EffectiveJava笔记(第一部分)
考虑用静态构造方法代替构造器的好处: 1.静态构造方法有名字 BigInteger.probablePrime(int, int, Random)比 new BigInteger(int, i ...
- [Effective Java]第二章 创建和销毁对象
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
随机推荐
- WijmoJS V2019.0 Update2发布:再度增强 React 和 Vue 框架的组件功能
前端开发工具包 WijmoJS 在2019年的第二个主要版本 V2019.0 Update2 已经发布,本次发布涵盖了React 和 Vue 框架下 WijmoJS 前端组件的功能增强,并加入更为易用 ...
- 在ASP.NET Core 2.0中使用Facebook进行身份验证
已经很久没有更新自己的技术博客了,自从上个月末来到天津之后把家安顿好,这个月月初开始找工作,由于以前是做.NET开发的,所以找的还是.NET工作,但是天津这边大多还是针对to B(企业)进行定制开发的 ...
- [ZJOI2010]数字计数 题解
题面 这道题是一道数位DP的模板题: 因为窝太蒟蒻了,所以不会递推,只会记忆化搜索: 首先,咋暴力咋来: 将一个数分解成一个数组,这样以后方便调用: 数位DP的技巧:(用1~b的答案)-(1~a的答案 ...
- Luogu P2495 [SDOI2011]消耗战
题目 我们可以很快的想到一个单次\(O(n)\)的dp. 然后我们注意到这个dp有很多无用的操作,比如一条没有关键点的链可以直接去掉. 所以我们可以尝试一次dp中只管那些有用的点. 题目给的关键点显然 ...
- thinkPHP连接数据库报错:PDOException in Connection.php line 295
跑去网上找了N多方法来尝试,重装apache.mysql.安装集成软件都试过了.错误一样. 后来细细分析,PDOException in Connection指的不就是PDO异常吗? 然后去了解了一些 ...
- Scalar Queries CodeForces - 1167F (计数,树状数组)
You are given an array $a_1,a_2,…,a_n$. All $a_i$ are pairwise distinct. Let's define function $f(l, ...
- 11-Perl 运算符
1.Perl 运算符运算符是一种告诉编译器执行特定的数学或逻辑操作的符号,如: 3+2=5.Perl 语言内置了丰富的运算符,我们来看下常用的几种: 算术运算符,比较运算符,逻辑运算符,赋值运算符,位 ...
- winfrom 点击按钮button弹框显示颜色集
1.窗体托一个按钮button: 2.单击事件: private void btnForeColor_Click(object sender, EventArgs e) { using (ColorD ...
- 去重复的sql(Oracle)
1.利用group by 去重复 2.可以利用下面的sql去重复,如下 1) select id,name,sex from (select a.*,row_number() over(partiti ...
- odoo 权限文件说明
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink (权限的定义)access_book_user ...