题目传送门
分析:
震惊!某沙茶选手写了一个多小时主席树套网络流拼信仰过题竟只能得到10分???
这是人性的泯灭,还是道德的沦丧?
然后只是主席树建边建挂了。。。
然而只有60分??
:wsm会T啊。。。
:1e5不T才怪
:A+B不是2e5都可以过吗???
:人家是5e4。。。
:。。。。
:而且人家时限6S,你这道还有多组数据
那真是对不起了。。。我去死一死
正解笛卡尔树。。。然后树形DP
对于每一个关键高度,只有两种情况:
溢出和没溢出
没溢出的话,这个点的祖先节点便不可能溢出
于是我们开始讨论,对于一个点:
1、他的两个儿子溢出,自己也溢出
2、他的两个儿子溢出,自己没溢出
3、他的两个儿子至少一个没有溢出
1和3可以很快出答案,但是2水位的高度多少为最优是可以总复杂度O(m)处理的
奥妙重重的细节操作就不赘述了,看代码吧
#include<cstdio> #include<cmath> #include<cstring> #include<algorithm> #include<map> #include<queue> #define maxn 200005 #define INF 0x3f3f3f3f using namespace std; inline long long getint() { long long num=0,flag=1;char c; while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1; while(c>='0'&&c<='9')num=num*10+c-48,c=getchar(); return num*flag; } int n,m,N; struct node{ int F,S; }a[maxn]; inline bool cmp(node x,node y){return x.F==y.F?x.S<y.S:x.F<y.F;} vector<node>P[maxn]; int f[maxn][20],fa[maxn],h[maxn],lc[maxn],rc[maxn]; int D[maxn],F[maxn],num[maxn]; inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);} int main() { int T=getint(); while(T--) { memset(num,0,sizeof num); memset(lc,0,sizeof lc),memset(rc,0,sizeof rc); for(int i=1;i<=N;i++)P[i].clear(); N=n=getint(),m=getint(); for(int i=1;i<n;i++)a[i].F=getint(),a[i].S=i; for(int i=1;i<=n;i++)fa[i]=i; sort(a+1,a+n,cmp); for(int i=1;i<n;i++) { int r1=find(a[i].S),r2=find(a[i].S+1); h[++N]=a[i].F,f[N][0]=0,fa[N]=N,lc[N]=r1,rc[N]=r2; fa[r1]=f[r1][0]=fa[r2]=f[r2][0]=N; } for(int j=1;j<20;j++)for(int i=1;i<=N;i++) f[i][j]=f[f[i][j-1]][j-1]; while(m--) { int x=getint(),y=getint(),k=getint(); for(int i=19;~i;i--)if(f[x][i]&&h[f[x][i]]<=y)x=f[x][i]; P[x].push_back((node){y,k});num[x]+=(!k); } for(int i=1;i<=N;i++)sort(P[i].begin(),P[i].end(),cmp); for(int i=1;i<=N;i++) { int tmp=F[i]=D[lc[i]]+D[rc[i]]+num[i],sz=P[i].size(); for(int j=0;j<sz;j++)F[i]=max((tmp+=(P[i][j].S?1:-1)),F[i]); D[i]=tmp,F[i]=max(F[i],F[lc[i]]+F[rc[i]]+num[i]); } printf("%d\n",F[N]); } }