#15

Timofey and Black-White Tree

题面

对于新增一个黑点,爆搜将其它所有点到黑点的距离都更新,如果遇到距离更小的或者当前的距离大于答案就不更新了。正确性显然,前者再往下搜肯定不如距离当前点的更小的那个点更新是优秀;后者对答案显然没有影响,因为再搜下去距离会更大。复杂度为 \(O(n\sqrt n)\),复杂度证明可以看 World_Creater的题解

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=2e5+10;
int n,m,c[N],dis[N],ans;
vector<int>e[N];
void bfs(int x){
    queue<int>q;
    q.push(x);
    dis[x]=0;
    while(q.size()){
        int u=q.front();
        if(dis[u]>=ans){
            return;
        }
        q.pop();
        for(auto v:e[u]){
            if(dis[v]>dis[u]+1){
                dis[v]=dis[u]+1;
                q.push(v);
            }
        }
    }
}
void solve(){
    read(n);
    ans=inf;
    for(int i=1;i<=n;i++){
        read(c[i]);
        dis[i]=inf;
        e[i].clear();
    }
    for(int i=1;i<n;i++){
        int u,v;
        read(u),read(v);
        e[u].pb(v);
        e[v].pb(u);
    }
    bfs(c[1]);
    for(int i=2;i<=n;i++){
        ans=min(ans,dis[c[i]]);
        write_space(ans);
        bfs(c[i]);
    }
    putchar('\n');
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t;
    read(t);
    while(t--){
        solve();
    }
    return 0;
}

Arpa’s overnight party and Mehrdad’s silent entering

题面

\(a_i\)\(b_i\) 间连一条边,限制 \(a_i\)\(b_i\) 的颜色不同。由于第二个限制,所以可以对于 \(i\in [1,2n)\),限制 \(i\)\(i+1\) 颜色不同。如果图是二分图,说明可行,否则不行。每个点的颜色就是二分图染色的颜色。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=4e5+10;
int n,a[N],b[N],col[N];
vector<int>e[N];
void dfs(int u,int c){
    col[u]=c;
    for(auto v:e[u]){
        if(!col[v]){
            dfs(v,3-c);
        }
        if(col[v]!=3-c){
            write_endl(-1);
            exit(0);
        }
    }
}
void solve(){
    read(n);
    for(int i=1;i<=n;i++){
        read(a[i]),read(b[i]);
        e[a[i]].pb(b[i]);
        e[b[i]].pb(a[i]);
        e[i*2].pb(i*2-1);
        e[i*2-1].pb(i*2);
    }
    for(int i=1;i<=n*2;i++){
        if(!col[i]){
            dfs(i,1);
        }
    }
    for(int i=1;i<=n;i++){
        write_space(col[a[i]]),write_endl(col[b[i]]);
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

Yet Another DAG Problem

题面

之前做了一个赋点权的题,不记得是哪道了,是用网络流做的,这题自然而然地就往网络流上想了。

先给出一个结论,\(a_i\) 是连续的。如果存在一个 \(k\) 满足存在 \(a_i>k,k>a_j\) 且不存在 \(a_p=k\),可以令大于 \(k\)\(a_i\rightarrow a_{i}-1\),这样 \(b_i\) 可以保证不增。`

将贡献 \(w\times(a_u-a_v)\) 拆开,拆成 \(w\times a_u-w\times a_v\),将 \(u\) 贡献增加 \(w\),将 \(v\) 贡献减少 \(w\)。建 \(n\) 条链,令 \((i,j)\) 表示 \(a_i\) 的权值为 \(j\),如果割掉第 \(j\) 条边,则说明权值选 \(j\)。为了保证 \(a_u>a_v\),可以对于 \(j\in[0,n)\),连一条 \((v,j)\rightarrow(u,j+1)\),权值为 \(+\infty\) 的边。最后从 \(S\) 开始跑残量网络,跑到的权值最大的点就是该点的答案。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define int long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e18;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=510,M=5e5+10;
int S,T,head[N],tot=1;
int n,m;
struct edge{
    int v,w,nxt;
}e[M<<1];
void add(int u,int v,int w){
    e[++tot].v=v;
    e[tot].w=w;
    e[tot].nxt=head[u];
    head[u]=tot;
}
void add_e(int u,int v,int w){
    add(u,v,w);
    add(v,u,0);
}
namespace Max_Flow{
    int cur[N<<1],dep[N<<1];
    bool bfs(){
        queue<int>q;
        for(int i=1;i<=T;i++){
            dep[i]=0;
        }
        dep[S]=1;
        q.push(S);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(int i=head[u];i;i=e[i].nxt){
                int v=e[i].v,w=e[i].w;
                if(!dep[v]&&w){
                    dep[v]=dep[u]+1;
                    if(v==T){
                        return 1;
                    }
                    q.push(v);
                }
            }
        }
        return 0;
    }
    int dfs(int u,int flow){
        if(u==T){
            return flow;
        }
        int ans=0;
        for(int i=cur[u];i;i=e[i].nxt){
            cur[u]=i;
            int v=e[i].v,w=e[i].w;
            if(dep[v]==dep[u]+1&&w){
                int res=dfs(v,min(flow,w));
                e[i].w-=res;
                e[i^1].w+=res;
                flow-=res;
                ans+=res;
            }
            if(!flow){
                break;
            }
        }
        if(!ans){
            dep[u]=0;
        }
        return ans;
    }
    int dinic(){
        int ans=0;
        while(bfs()){
            for(int i=1;i<=T;i++){
                cur[i]=head[i];
            }
            ans+=dfs(S,inf);
        }
        return ans;
    }
}
int val[N],id[N][N],vis[N*N],idx,mx=1e9;
void dfs(int u){
    vis[u]=1;
    for(int i=head[u];i;i=e[i].nxt){
        int v=e[i].v,w=e[i].w;
        if(w&&!vis[v]){
            dfs(v);
        }
    }
}
void solve(){
    read(n),read(m);
    for(int i=1;i<=n;i++){
        for(int j=0;j<=n;j++){
            id[i][j]=++idx;
        }
    }
    S=++idx,T=++idx;
    for(int i=1;i<=n;i++){
        add_e(S,id[i][0],inf);
        add_e(id[i][n],T,inf);
    }
    for(int i=1;i<=m;i++){
        int u,v,w;
        read(u),read(v),read(w);
        val[u]+=w;
        val[v]-=w;
        for(int i=0;i<n;i++){
            add_e(id[v][i],id[u][i+1],inf);
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<n;j++){
            add_e(id[i][j],id[i][j+1],val[i]*j+mx);
        }
    }
    Max_Flow::dinic();
    dfs(S);
    for(int i=1;i<=n;i++){
        for(int j=n;j>=0;j--){
            if(vis[id[i][j]]){
                write_space(j);
                break;
            }
        }
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

Pawns

题面

因为只能往右移,令 \(b_i=y_i-|x_i-k|\),最终落点 \(a_i\) 一定大于等于 \(b_i\)。可以得到的是一定是一段前缀的后缀最大值,前缀的右端点可以用 set 维护,后缀最大值可以用线段树维护,复杂度 \(O(n\log n)\)

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
const int N=4e5+10;
int n,k,q,m;
struct node{
    int sum,rmx;        
}tr[N<<2];
namespace Seg_Tree{
    int ls(int p){
        return p<<1;
    }
    int rs(int p){
        return p<<1|1;
    }
    void push_up(int p){
        tr[p].sum=tr[ls(p)].sum+tr[rs(p)].sum;
        tr[p].rmx=max(tr[rs(p)].rmx,tr[ls(p)].rmx+tr[rs(p)].sum);
    }
    void build(int p,int l,int r){
        tr[p].sum=tr[p].rmx=-1;
        if(l==r){
            return;
        }
        int mid=(l+r)>>1;
        build(ls(p),l,mid);
        build(rs(p),mid+1,r);
        push_up(p);
    }
    void update(int p,int l,int r,int pos,int val){
        if(l==r){
            tr[p].sum+=val;
            tr[p].rmx+=val;
            return;
        }
        int mid=(l+r)>>1;
        if(pos<=mid){
            update(ls(p),l,mid,pos,val);
        }
        else{
            update(rs(p),mid+1,r,pos,val);
        }
        push_up(p);
    }
    node query(int p,int l,int r,int pos){
        if(r<=pos){
            return tr[p];
        }
        int mid=(l+r)>>1;
        if(pos<=mid){
            return query(ls(p),l,mid,pos);
        }
        node res,ansl,ansr;
        ansl=query(ls(p),l,mid,pos);
        ansr=query(rs(p),mid+1,r,pos);
        res.sum=ansl.sum+ansr.sum;
        res.rmx=max(ansr.rmx,ansl.rmx+ansr.sum);
        return res;
    }
}
multiset<int>s;
map<pii,bool>vis;
void solve(){
    read(n),read(k),read(q);
    m=n+q;
    Seg_Tree::build(1,1,m);
    while(q--){
        int x,y;
        read(x),read(y);
        int opt=vis[mp(x,y)]?-1:1,p=y+abs(k-x);
        vis[mp(x,y)]+=opt;
        Seg_Tree::update(1,1,m,p,opt);
        // cerr<<x<<' '<<y<<' '<<opt<<endl;
        if(opt==1){
            s.insert(p);
        }
        else{
            s.erase(s.find(p));
        }
        if(!s.size()){
            write_endl(0);
            continue;
        }
        int mx=max(n,*(--s.end()));
        node res=Seg_Tree::query(1,1,m,mx);
        write_endl(max(0,mx-n+res.rmx));
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}

[ABC308G] Minimum Xor Pair Query

题面

好题。但是真学ds学的了,一眼线段树分治+trie。

这题有个关键性结论:若存在 \(x<y<z\)\(\min(x\oplus y,y\oplus z)\le x\oplus z\)。证明的话,将所有数放到trie上,对于一个数,如果找其的异或最小值,一定贪心的往当前位的值的方向走,即会走到排序后与它相邻的点。

用两个set,一个维护值,一个维护相邻两个数的异或和。

点击查看代码
#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define pii pair<int,int>
#define pdi pair<double,int>
#define pb push_back
#define eps 1e-9
#define mp make_pair
using namespace std;
const int inf=1e9;
namespace IO{
    template<typename T>
    inline void read(T &x){
        x=0;
        int f=1;
        char ch=getchar();
        while(ch>'9'||ch<'0'){
            if(ch=='-'){
                f=-1;
    }
            ch=getchar();
        }
        while(ch>='0'&&ch<='9'){
            x=x*10+(ch-'0');
            ch=getchar();
        }
        x=(f==1?x:-x);
    }
    template<typename T>
    inline void write(T x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>=10){
            write(x/10);
        }
        putchar(x%10+'0');
    }
    template<typename T>
    inline void write_endl(T x){
        write(x);
        putchar('\n');
    }
    template<typename T>
    inline void write_space(T x){
        write(x);
        putchar(' ');
    }
}
using namespace IO;
multiset<int>s,val;
int n;
void solve(){
    read(n);
    for(int i=1;i<=n;i++){
        // cerr<<i<<endl;
        int opt,x;
        read(opt);
        if(opt==1){
            read(x);
            if(!val.size()){
                val.insert(x);
                continue;
            }
                // cerr<<"HAHA"<<endl;
            int mn=*val.begin();
            if(x<mn){
                s.insert(mn^x);
                val.insert(x);
                continue;
            }
            auto it=val.lower_bound(x);
            if(it==val.end()){
                it--;
                s.insert((*it)^x);
                val.insert(x);
                continue;
            }
            int y=*it,z=*(--it);
            val.insert(x);
            s.insert(y^x);
            s.insert(z^x);
            s.erase(s.find(y^z));
        }
        else if(opt==2){
            read(x);
            val.erase(val.find(x));
            if(!val.size()){
                continue;
            }
            int mn=*val.begin();
            if(x<mn){
                s.erase(s.find(mn^x));
                continue;
            }
            auto it=val.lower_bound(x);
            if(it==val.end()){
                it--;
                s.erase(s.find((*it)^x));
                continue;
            }
            int y=*it,z=*(--it);
            s.erase(s.find(y^x));
            s.erase(s.find(z^x));
            s.insert(y^z);
        }
        else{
            write_endl(*s.begin());
        }
    }
}
signed main(){
    #ifndef ONLINE_JUDGE
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    int t=1;
    while(t--){
        solve();
    }
    return 0;
}
posted @ 2023-10-23 20:46  luo_shen  阅读(35)  评论(0)    收藏  举报