数据结构专项测试2

考完就会T2和T3 40pts了...

T1 5a2m5Yab6aKY

不会。


T2 Q0Y1NzFE

\(std\) 给的做法是在线的,按秩合并并查集,不路径压缩,记录每个点被接到父亲上的时间并在并查集上打标记,每次询问暴跳父亲,如果标记时间合法就更新。

午休时20分钟yy了个离线。离线操作后建出两个并查集的树,第一类建主席树,第二类建线段树,在第二类上打上时间标记,然后在第一类上做子树修改,查询时直接查合法时间区间就好。

写了个 \(std\) 的。

\(code:\)

T2
#include<bits/stdc++.h>
using namespace std;

namespace IO{
    typedef long long LL;
    #define int LL
    int read(){
        int x=0,f=0; char ch=getchar();
        while(ch<'0'||ch>'9'){ f|=(ch=='-'); ch=getchar(); }
        while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return f?-x:x;
    } char output[50];
    void write(int x,char sp){
        int len=0;
        if(x<0) x=-x,putchar('-');
        do{ output[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(output[i]); putchar(sp);
    }
    void ckmax(int& x,int y){ x=x>y?x:y; }
    void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const int NN=500010;
int n,m,clr[NN];
char op;
vector<pair<int,int>>tag[NN];

struct DSU{
    int fa[NN],tim[NN],siz[NN];
    void prework(){
        for(int i=1;i<=n;i++)
            fa[i]=i, siz[i]=1;
    }
    int getf(int x){ return x==fa[x]?x:getf(fa[x]); }
    void merge(int x,int y,int t){
        x=getf(x); y=getf(y);
        if(x==y) return;
        if(siz[x]<siz[y]) swap(x,y);
        tim[y]=t; fa[y]=x; siz[x]+=siz[y];
    }
}s1,s2;

signed main(){
    n=read(); m=read();
    s1.prework(); s2.prework();
    for(int i=1;i<=n;i++) tag[i].push_back({-1,0});
    for(int x,t=1;t<=m;t++){
        cin>>op;
        if(op=='U') s1.merge(read(),read(),t);
        else if(op=='M') s2.merge(read(),read(),t);
        else if(op=='A') x=s1.getf(read()), tag[x].push_back({t,tag[x].back().second+s1.siz[x]});
        else if(op=='Z') x=s2.getf(read()), clr[x]=t;
        else{
            x=read();
            int tim=clr[x],ans=0,tme;
            for(int u=x;u!=s2.fa[u];u=s2.fa[u])
                if(clr[s2.fa[u]]>s2.tim[u]) ckmax(tim,clr[s2.fa[u]]);
            tme=upper_bound(tag[x].begin(),tag[x].end(),make_pair(tim,0ll))-tag[x].begin()-1;
            ans=tag[x].back().second-tag[x][tme].second;
            for(int u=x;u!=s1.fa[u];u=s1.fa[u]){
                int f=s1.fa[u];
                tme=upper_bound(tag[f].begin(),tag[f].end(),make_pair(max(tim,s1.tim[u]),0ll))-tag[f].begin()-1;
                ans+=tag[f].back().second-tag[f][tme].second;
            }
            write(ans,'\n');
        }
    }
    return 0;
}

T3 U1BPSiBDT1Q2

先考虑 \(O(n^2)\)\(DP\) ,设 \(f_u\)\(u\) 做链终点(从下往上)时 \(u\) 子树的最优解,那么有

\[f_u=min_{v\in subtree}\left\{\operatorname{sum}^2(u,v)+\sum_{p\in points}f_p\right\} \]

其中 \(\operatorname{sum}(u,v)\)\(u,v\) 路径上点权之和, \(subtree\)\(u\) 的子树, \(points\)\(u\)\(v\) 链上所有点不在链上的儿子。

考虑优化。设 \(val_u=\operatorname{sum}(1,u)\) ,那么有

\[f_u=min_{v\in subtree}\left\{(val_v-val_{fa_u})^2+\sum_{p\in points}f_p\right\} \]

展开式子,有

\[f_u=val_v^2-2\times val_v\times val_{fa_u}+val_{fa_u}^2+\sum_{p\in points}f_p \\ 2val_{fa_u}\times val_v+f_u-val_{fa_u}^2=val_v^2+\sum_{p\in points}f_p \]

这样就化成了斜率优化的形式,对每个点,以 \((val_u,val_u^2+\sum_{p\in points}f_p)\) 为坐标放入 set 中动态维护凸包,求值的时候二分斜率求切线即可。

子树合并时找到重儿子,继承重儿子的 set ,这时重儿子的 \(\sum f\) 会少算,于是将 \(y\) 轴整体平移。

打标记的操作很精妙。

\(code:\)

T3
#include<bits/stdc++.h>
using namespace std;

namespace IO{
    #define int long long
    #define mp make_pair
    #define fi first
    #define se second
    typedef pair<int,int> PII;
    int read(){
        int x=0,f=0; char ch=getchar();
        while(ch<'0'||ch>'9'){ f|=(ch=='-'); ch=getchar(); }
        while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return f?-x:x;
    } char output[50];
    void write(int x,char sp){
        int len=0;
        if(x<0) x=-x,putchar('-');
        do{ output[len++]=x%10+'0'; x/=10; }while(x);
        for(int i=len-1;~i;i--) putchar(output[i]); putchar(sp);
    }
    void ckmax(int& x,int y){ x=x>y?x:y; }
    void ckmin(int& x,int y){ x=x<y?x:y; }
} using namespace IO;

const int NN=1000010;
int n,f[NN],fa[NN],val[NN],tag[NN],sum[NN];
vector<int>e[NN];
int sqr(int x){ return x*x; }

namespace Hull{
    set<PII>s[NN];
    double slope(PII x,PII y){ return 1.0*(x.se-y.se)/(x.fi-y.fi); }
    bool cmp(PII x,PII y,PII z){ return slope(x,y)<slope(y,z); }
    void insert(int i,PII P){
        P.se-=tag[i];
        auto p=s[i].lower_bound(P);
        if(p!=s[i].end()&&p->fi==P.fi)
            if(p->se<=P.se) return;
            else s[i].erase(p);
        while(!s[i].empty()){
            p=s[i].lower_bound(P);
            if(p==s[i].begin()) break;
            --p;
            if(p==s[i].begin()) break;
            auto q=p; --p;
            if(!cmp(*p,*q,P)) s[i].erase(q);
            else break;
        }
        while(!s[i].empty()){
            p=s[i].lower_bound(P);
            if(p==s[i].end()) break;
            auto q=p; ++p;
            if(p==s[i].end()) break;
            if(!cmp(P,*q,*p)) s[i].erase(q);
            else break;
        }
        p=s[i].lower_bound(P);
        if(p==s[i].begin()||p==s[i].end())
            return s[i].insert(P),void();
        auto q=p; --p;
        if(cmp(*p,P,*q)) s[i].insert(P);
    }
    int calc(int u){
        if(s[u].empty()) return LLONG_MAX;
        PII ans;
        if(s[u].size()==1) ans=*s[u].begin();
        else{
            int l=s[u].begin()->fi,r=(--s[u].end())->fi,mid;
            while(l<r){
                mid=l+r+1>>1;
                auto p=s[u].lower_bound(mp(mid,-LLONG_MAX));
                if(p==s[u].begin()) l=mid;
                else{
                    PII R=*p; PII L=*(--p);
                    L.se+=tag[u]; R.se+=tag[u];
                    if(slope(L,R)<2*val[fa[u]]) l=mid;
                    else r=mid-1;
                }
            }
            ans=*s[u].lower_bound(mp(l,-LLONG_MAX));
        }
        ans.se+=tag[u];
        return sqr(val[fa[u]])-2*val[fa[u]]*ans.fi+ans.se;
    }
} using namespace Hull;

void dfs(int u){
    val[u]+=val[fa[u]];
    int sum=0,son=0;
    for(int v:e[u]){
        dfs(v); sum+=f[v];
        if(s[v].size()>s[son].size()) son=v;
    }
    swap(s[u],s[son]); tag[u]=tag[son]+sum-f[son];
    for(int v:e[u]) if(v^son){
        tag[v]+=sum-f[v];
        for(PII x:s[v]) x.se+=tag[v], insert(u,x);
    }
    f[u]=min(calc(u),sum+sqr(val[u]-val[fa[u]]));
    insert(u,mp(val[u],sum+sqr(val[u])));
}

signed main(){
    n=read();
    for(int i=1;i<=n;i++) val[i]=read();
    for(int i=2;i<=n;i++) e[fa[i]=read()].push_back(i);
    dfs(1); write(f[1],'\n');
    return 0;
}
posted @ 2021-12-19 19:43  keen_z  阅读(23)  评论(0编辑  收藏  举报