• CF1495F Squares


    一、题目

    点此看题

    二、解法

    考虑每次增删格子会有什么影响,快速求 ((x,y)) 之间的最短路就可以解决修改了。

    我们把第二种边看成区间 ([l,r]),也就是 (r)(l) 后面第一个满足 (p_r>p_l) 的点,现在考虑用区间去替换原来 (i)(i+1) 的边,可以把一个区间的权值定义成 (b[l]-(a[r-1]-a[l-1])),问题是选出不交的区间使得权值最小。

    如果没有什么性质是做不动的,结论是:这些区间不会有交。考虑反证法,设四个端点 (x_1<x_2<x_3<x_4),如果 ([x_1,x_3])([x_2,x_4]) 分别构成区间,那么 (p_1>p_2,p_1<p_3,p_2>p_3),矛盾。

    知道这个性质以后可以考虑离线,如果 ([l,r]) 比里面记录区间的最优方案的总权值还要小,那么直接替换,因为区间不交所以 ([r,n+1]) 的最短路都会受到这次替换的影响,用树状数组实现即可,时间复杂度 (O(nlog n))

    三、总结

    如果有两种决策(或多种)的问题可以考虑主一副二的方法,先固定一个然后用另一个来调整最优解。

    当发现是一个做不动的问题时,可以主动去寻找结论,比如本题我们寻找关于区间的性质。

    #include <cstdio>
    #include <vector>
    #include <iostream>
    #include <set>
    using namespace std;
    const int M = 200005;
    const int inf = 1e9;
    #define pii pair<int,int>
    #define make make_pair
    #define int long long
    int read()
    {
    	int x=0,f=1;char c;
    	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
    	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    	return x*f;
    }
    int n,m,q,p[M],a[M],b[M],to[M],st[M],id[M];
    set<int> s;vector<pii> v[M];int ans[M],bit[M];
    int lowbit(int x)
    {
        return x&(-x);
    }
    int ask(int x)
    {
        int r=0;
        for(int i=x;i>=1;i-=lowbit(i))
            r+=bit[i];
        return r;
    }
    void add(int x,int y)
    {
        for(int i=x;i<=n+1;i+=lowbit(i))
            bit[i]+=y;
    }
    signed main()
    {
        n=read();q=read();
        for(int i=1;i<=n;i++)
            p[i]=read();
        for(int i=1;i<=n;i++)
            a[i]=read()+a[i-1];//prefix sum
        for(int i=1;i<=n;i++)
            b[i]=read();
        st[++m]=inf;id[m]=n+1;
        for(int i=n;i>=1;i--)//maintain a stack
        {
            int l=1,r=m;
            while(l<=r)
            {
                int mid=(l+r)>>1;
                if(st[mid]>p[i])
                {
                    to[i]=id[mid];
                    l=mid+1;
                }
                else r=mid-1;
            }
            while(p[i]>=st[m]) m--;
            st[++m]=p[i],id[m]=i;
            b[i]-=a[to[i]-1]-a[i-1];//rewrite the value
        }
        s.insert(1);s.insert(n+1);
        v[1].push_back(make(n+1,0));
        for(int i=1;i<=q;i++)//off line
        {
            int x=read();
            if(x==1) continue;
            if(s.find(x)==s.end())
            {
                auto it=s.lower_bound(x);
                int r=*it;it--;int l=*it;
                v[l].push_back(make(r,-i));
                v[l].push_back(make(x,i));
                v[x].push_back(make(r,i));
                s.insert(x);
            }
            else
            {
                s.erase(x);
                auto it=s.lower_bound(x);
                int r=*it;it--;int l=*it;
                v[l].push_back(make(r,i));
                v[l].push_back(make(x,-i));
                v[x].push_back(make(r,-i));
            }
        }
        for(int i=n;i>=1;i--)
        {
            int x=ask(to[i]);
            if(x>b[i]) add(to[i],b[i]-x);
            for(auto y:v[i])
            {
                if(y.second>=0)
                    ans[y.second]+=ask(y.first)+a[y.first-1]-a[i-1];
                else
                    ans[-y.second]-=ask(y.first)+a[y.first-1]-a[i-1];
            }
        }
        for(int i=1;i<=q;i++)
        {
            ans[i]+=ans[i-1];
            printf("%lld
    ",ans[i]);
        }
    }
    
    
  • 相关阅读:
    谈谈Windows Wow64
    Windows x86 下的 静态代码混淆
    Android so 文件进阶<二> 从dlsym()源码看android 动态链接过程
    You should blog even if you have no readers
    android app启动过程
    Android so文件进阶 <一>
    AndroidStudio+ideasmali动态调试smali汇编
    32位进程注入64位进程
    What is Windows Clustering
    Delphi实用小function
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/14968568.html
Copyright © 2020-2023  润新知