难得遇到一个不卡常的,,
维护一个小根堆,堆里是当前有的骑士,按dfs序,所有不能攻占该城市的都弹出,城市阻挡人数++,这个人攻占的城市=depth[出生城市]-depth[该城市];然后把可以攻占的加标记和乘标记更新后再向上合并到它的父节点。所以,我们需要一个支持合并的小根堆。左偏堆板子一套,美滋滋。然后,成功把根攻占的骑士攻占城市数=depth[出生城市]。然后直接输出即可。
最多m次合并,每次最多带n个人,O(mn);初始插入O(mlogm),每个人最多弹1次,O(mlogm)。综上,就是O(mn+mlogm)。
代码,,一如既往地丑,,
#include<bits/stdc++.h> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<algorithm> #include<queue> #include<deque> #include<list> #include<set> #include<vector> #include<iostream> #define ll long long #define re register #define inf 0x7f7f7ff #define inl inline #define sqr(x) (x*x) //#define eps 1e-8 #define debug printf("debug "); //#pragma comment(linker, "/STACK:1024000000,1024000000") //#pragma GCC optimize (2) //#pragma G++ optimize (2) using namespace std; //const ll mod; const ll MAXN=3e5+10; inl ll read() { re ll x = 0; re int f = 1; char ch = getchar(); while(ch<'0'||ch>'9') { if(ch== '-' ) f = -1; ch = getchar(); } while(ch>='0'&&ch<='9') {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x * f; } inl char readc() { char ch=getchar(); while(('z'<ch||ch<'a')&&('Z'<ch||ch<'A')) ch=getchar(); return ch; } inl void write(re ll x){ if(x>=10)write(x/10); putchar(x%10+'0'); } inl void writeln(re ll x){ if(x<0) {x=-x;putchar('-');} write(x); puts(""); } inl ll gcd(re ll x,re ll y){while(y^=x^=y^=x%=y);return x;} inl ll Lcm(re ll a,re ll b) {return a/gcd(a,b)*b;} inl void FR() { freopen(".in","r",stdin); freopen(".out","w",stdout); } inl void FC() { fclose(stdin); fclose(stdout); } struct Node { ll ls,rs,dis,val; ll add,mul; }Tree[MAXN]; inl void cov(ll x,ll add,ll mul) { Tree[x].val*=mul;Tree[x].val+=add; Tree[x].add*=mul;Tree[x].mul*=mul;Tree[x].add+=add; } inl void pushdown(ll x) { cov(Tree[x].ls,Tree[x].add,Tree[x].mul); cov(Tree[x].rs,Tree[x].add,Tree[x].mul); Tree[x].add=0;Tree[x].mul=1; } ll merge(ll a,ll b) { if(!a||!b) return a^b; pushdown(a),pushdown(b); if(Tree[a].val>Tree[b].val) swap(a,b); Tree[a].rs=merge(Tree[a].rs,b); if(Tree[Tree[a].ls].dis<Tree[Tree[a].rs].dis) swap(Tree[a].ls,Tree[a].rs); Tree[a].dis=Tree[Tree[a].rs].dis+1; return a; } ll n,m,cnt,head[MAXN],h[MAXN],depth[MAXN]; ll rt[MAXN],a[MAXN],v[MAXN],c[MAXN],ans[2][MAXN]; struct edge { ll u,v,nxt; }e[MAXN]; inl void adde(ll u,ll v) { e[++cnt].u=u;e[cnt].v=v; e[cnt].nxt=head[u];head[u]=cnt; } void dfs(ll x,ll fa) { for(re ll hs=head[x];hs;hs=e[hs].nxt) { re ll sv=e[hs].v; depth[sv]=depth[x]+1; dfs(sv,x);rt[x]=merge(rt[x],rt[sv]); } while(rt[x]&&Tree[rt[x]].val<h[x]) { pushdown(rt[x]); ++ans[0][x];ans[1][rt[x]]=depth[c[rt[x]]]-depth[x]; rt[x]=merge(Tree[rt[x]].ls,Tree[rt[x]].rs); } if(a[x]) cov(rt[x],0,v[x]); else cov(rt[x],v[x],1); } int main() { // FR(); n=read(),m=read(); for(re ll i=1;i<=n;i++) h[i]=read(); for(re ll i=2;i<=n;i++) { re ll f=read();adde(f,i); a[i]=read(),v[i]=read(); } for(re ll i=1;i<=m;i++) { Tree[i].val=read(),c[i]=read(); Tree[i].mul=1;rt[c[i]]=merge(rt[c[i]],i); } depth[1]=1;dfs(1,0); while(rt[1]) { pushdown(rt[1]);ans[1][rt[1]]=depth[c[rt[1]]]; rt[1]=merge(Tree[rt[1]].ls,Tree[rt[1]].rs); } for(re ll i=1;i<=n;i++) writeln(ans[0][i]); for(re ll i=1;i<=m;i++) writeln(ans[1][i]); // FC(); return 0; }