LG P3261 [JLOI2015]城池攻占(左偏树)

130 篇文章 1 订阅
124 篇文章 0 订阅

题目
在dfs的过程中把所有能到达这个城池的骑士用可并堆存储。
然后把不能通过该城池的弹走。
堆上打标记真是666.
加个快读快了10倍。。。。

#include<bits/stdc++.h>
#define maxn 300005
#define LL long long
using namespace std;

char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &res){
	char ch;bool f = 0;
	for(;!isdigit(ch=getc());) if(ch=='-') f=1;
	for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
	(f) && (res=-res);
}

int n,m,f[maxn],ch[maxn][2];
LL h[maxn],a[maxn],v[maxn],s[maxn],add[maxn],mul[maxn];
vector<int>G[maxn];
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int rt[maxn],d[maxn];
int ans1[maxn],ans2[maxn],adda[maxn];

void dt(int x){
	if(add[x] || mul[x]!=1){
		s[x] = s[x] * mul[x] + add[x];
		if(ch[x][0]) 
			mul[ch[x][0]] *= mul[x] , add[ch[x][0]] *= mul[x] , add[ch[x][0]] += add[x];
		if(ch[x][1]) 
			mul[ch[x][1]] *= mul[x] , add[ch[x][1]] *= mul[x] , add[ch[x][1]] += add[x];
		add[x] = 0 , mul[x] = 1;
	}
	if(adda[x]){
		ans2[x] += adda[x];
		if(ch[x][0]) adda[ch[x][0]] += adda[x];
		if(ch[x][1]) adda[ch[x][1]] += adda[x];
		adda[x] = 0;
	}
}

void merge(int &now,int u,int v){
	dt(u) , dt(v);
	if(!u || !v){now = u|v; return;}
	else if(s[u] < s[v]) now = u , merge(ch[now][1],ch[u][1],v);
	else now = v , merge(ch[now][1],u,ch[v][1]);
	if(d[ch[now][1]] > d[ch[now][0]]) swap(ch[now][1],ch[now][0]);
	d[now] = d[ch[now][1]] + 1;
}

void dfs(int now,int ff){
	for(int i=0,siz=G[now].size();i<siz;i++)
		merge(rt[now],rt[now],G[now][i]);
	for(int i=info[now];i;i=Prev[i])
		if(to[i]!=ff){
			dfs(to[i],now);
			merge(rt[now],rt[now],rt[to[i]]);
		}
	for(;rt[now] && s[rt[now]] < h[now];dt(rt[now]),merge(rt[now],ch[rt[now]][0],ch[rt[now]][1]))
		ans1[now] ++;
	adda[rt[now]]++,add[rt[now]]+=a[now],mul[rt[now]]*=v[now];
}

void dfs(int now){
	if(!now) return;
	dt(now);
	dfs(ch[now][0]),dfs(ch[now][1]);
}

int main(){
	read(n),read(m);
	for(int i=1;i<=n;i++) read(h[i]);
	for(int i=2;i<=n;i++)
	{
		read(f[i]),read(a[i]),read(v[i]),Node(f[i],i);
		if(a[i] == 0) a[i] = v[i] , v[i] = 1;
		else a[i] = 0;
	}
	for(int i=1;i<=m;i++)
	{
		mul[i]=1;
		int c;
		read(s[i]),read(c);
		G[c].push_back(i);
	}
	dfs(1,0);
	for(int i=1;i<=n;i++)
		printf("%d\n",ans1[i]);
	dfs(rt[1]);
	for(int i=1;i<=m;i++) 
		printf("%d\n",ans2[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值