「雅礼集训 2017 Day2」水箱

题目传送门

分析:

震惊!某沙茶选手写了一个多小时主席树套网络流拼信仰过题竟只能得到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]);
    }
}
View Code

猜你喜欢

转载自www.cnblogs.com/Darknesses/p/12104727.html