• [做题记录]线段树


    省选阶段的线段树题。

    CF765F Souvenirs

    我们使用扫描线,先只考虑\(a_j > a_r\)的情况,我们考虑先找到离\(r\)最近的\(j\)
    那么此时对\([1,j]\)取一个\(a_j - a_r\)\(min\)

    然后我们思考如果\(i > j\)\(a_i - a_r\)能更新的话,则有\(a_i - a_r < a_j - a_r\),且有\(a_j - a_i > a_i - a_r\)

    则可计算出\(a_r \leq a_i \leq \frac{a_r + a_j}{2}\)

    然后我们发现其每次都减少一半值域。

    我们直接找并线段树取min修改,找的过程需要主席树 \(O(nlog^2n)\)

    CF765F Souvenirs
    #include<bits/stdc++.h>
    #define ll long long 
    #define N 100005
    #define LIM 1000000105
    
    int n;
    
    int a[N];
    
    int head[N];
    
    int ch[N * 40][2];
    
    int T[N * 40];
    
    #define ls(x) ch[x][0]
    #define rs(x) ch[x][1]
    #define mid ((1ll * l + 1ll * r) >> 1)
    
    inline void up(int x){T[x] = std::max(T[ls(x)],T[rs(x)]);}
    
    int cnt;
    
    inline void add(int lasu,int &u,int l,int r,int to,int p){
    	if(!u)u = ++cnt;
    	if(l == r){
    	T[u] = std::max(T[u],p);
    	return ;
    	}
    	if(to <= mid)
    	rs(u) = rs(lasu),add(ls(lasu),ls(u),l,mid,to,p);
    	else
    	ls(u) = ls(lasu),add(rs(lasu),rs(u),mid + 1,r,to,p);
    	up(u);
    //	std::cout<<lasu<<" "<<u<<" "<<l<<" "<<r<<" "<<to<<" "<<p<<" "<<T[u]<<std::endl;	
    }
    
    inline int find(int u,int l,int r,long double tl,long double tr){
    	if(l > tr)return 0; 
    	if(tl <= l && r <= tr)
    	return T[u];
    	int ans = 0;
    	if(tl <= mid)
    	ans = std::max(ans,find(ls(u),l,mid,tl,tr));
    	if(tr > mid)
    	ans = std::max(ans,find(rs(u),mid + 1,r,tl,tr));
    	return ans;
    }
    
    int F[N << 2];
    
    #define Ls(x) (x << 1)
    #define Rs(x) (x << 1 | 1)
    
    inline void cover(int u,int l,int r,int tl,int tr,int p){
    //	std::cout<<u<<" "<<l<<" "<<r<<" "<<tl<<" "<<tr<<" "<<p<<std::endl; 
    	if(tl <= l && r <= tr){
    		F[u] = std::min(F[u],p);
    		return ;
    	}
    	if(tl <= mid)
    	cover(Ls(u),l,mid,tl,tr,p);
    	if(tr > mid)
    	cover(Rs(u),mid + 1,r,tl,tr,p);
    } 
    
    inline int fans(int u,int l,int r,int t){
    //	std::cout<<u<<" "<<l<<" "<<r<<" "<<t<<" "<<F[u]<<std::endl;
    	if(l == r)
    	return F[u];
    	if(t <= mid)
    	return std::min(F[u],fans(Ls(u),l,mid,t));
    	if(t > mid)
    	return std::min(F[u],fans(Rs(u),mid + 1,r,t));	
    }
    
    inline void clear(){
    	std::memset(head,0,sizeof(head));
    	std::memset(ch,0,sizeof(ch));
    	std::memset(T,0,sizeof(T));	
    	std::memset(F,0x3f,sizeof(F));				
    	cnt = 0;
    }
    
    int m;
    
    std::vector< std::pair<int,int> >Q[N];
    
    int f[N * 3];
    
    inline void del(){
    	for(int r = 2;r <= n;++r){
    //		std::cout<<"! "<<r<<std::endl;
    		long double las = a[r];
    		int k = find(head[r - 1],1,LIM,las,LIM);
    		int a_las = a[k];
    //		std::cout<<"("<<a[r]<<" "<<LIM<<") -> "<<a_las<<std::endl;
    		las = (a[r] + a_las) * 0.5;
    		if(k != 0)
    		cover(1,1,n,1,k,(a_las - a[r]));
    		while((las - a[r]) >= 1){
    		k = find(head[r - 1],1,LIM,a[r],las);
    		a_las = a[k];
    //		std::cout<<"("<<a[r]<<" "<<las<<") -> "<<a_las<<std::endl;
    		if(k != 0)		
    		cover(1,1,n,1,k,(a_las - a[r]));	
    		las = (a[r] + a_las) * 0.5;
    		}		
    		for(int i = 0;i < Q[r].size();++i){
    //		std::cout<<"Q( "<<Q[r][i].first<<" "<<fans(1,1,n,Q[r][i].first)<<std::endl;
    		f[Q[r][i].second] = std::min(fans(1,1,n,Q[r][i].first),f[Q[r][i].second]);			
    		}
    	}
    }
    
    int main(){
    	std::memset(f,0x3f,sizeof(f));	
    	scanf("%d",&n);
    	for(int i = 1;i <= n;++i)
    	scanf("%d",&a[i]);
    	scanf("%d",&m);	
    	for(int i = 1;i <= m;++i){
    		int l,r;
    		scanf("%d%d",&l,&r);
    		Q[r].push_back(std::make_pair(l,i));
    	}
    	clear();
    	for(int i = 1;i <= n;++i){
    		add(head[i - 1],head[i],1,LIM,a[i],i);
    	}
    	del();
    	for(int i = 1;i <= n;++i)
    	a[i] = LIM - a[i];
    	clear();
    	for(int i = 1;i <= n;++i){
    		add(head[i - 1],head[i],1,LIM,a[i],i);
    	}
    	del();
    	for(int i = 1;i <= m;++i)
    	std::cout<<f[i]<<std::endl;	
    }
    

    CF280D k-Maximum Subsequence Sum

    刚开始一直在想能不能\(dp\),并写作矩阵形式。

    但是是错误的想法。

    考虑这是一个费用流模型,我们把\(i\)\(i + 1\)连一条流量为\(1\),费用为\(a_i / 0\)的边,然后\(S\)\(l\)连一条流量\(k\)的边,然后取最大费用流。

    但是无法直接流,那我们自然思考模拟费用流。

    即提供反悔关系,我们每次把选中的最大字段和区间加入答案并取反即可。

    代码太难写了,咕咕咕咕咕。

    [Code+#1]Yazid 的新生舞会

    捏马马的,自闭了兄弟。

    考虑枚举最终众数\(x\),把\(a[i] = x\)\(val\)设为\(1\),否则为\(-1\),等同于区间和大于\(0\)的区间数量。

    考虑\(1\)的个数只有\(O(n)\)个。

    我们自然考虑对每个等差数列求答案。

    那么有\(\sum_{x}^y T_i\)

    考虑写\(G_i = \sum T_i\)

    那么即\(G_i\)为三阶前缀和。

    考虑单点修改,维护三阶前缀和即可。

    image

    [Code+#1]Yazid 的新生舞会
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int INF = 0x3f3f3f3f;
    const LL mod = 1e9 + 7;
    const int N = 500005;
    // 修改差分 来维护前缀和的前缀和
    // c1 为差分d c2为d*i  c3 为d*i*i
    LL c1[N * 2], c2[N * 2], c3[N * 2];
    LL sum(int x) {
        LL res = 0;
        for (int i = x; i > 0; i -= i & -i) {
            res += c1[i] * (x + 2) * (x + 1) - c2[i] * (2 * x + 3) + c3[i];
        }
        return res / 2;
    }
    void add(int x, LL d, int n) {
        for (int i = x; i <= n; i += i & -i) {
            c1[i] += d;
            c2[i] += d * x;
            c3[i] += d * x * x;
        }
    }
    int a[N];
    vector<int> b[N];
    int main() {
        int n;
        scanf("%d%*d", &n);
        for (int i = 1; i <= n; i++) {
            scanf("%d", &a[i]);
            b[a[i]].push_back(i);
        }
        const int wc = n + 1;  // 偏移量,把[-n,n] 平移到 [1,2n+1]
        LL ans = 0;
        for (int i = 0; i < n; i++) {
            b[i].push_back(n + 1);
            int last = 0;
            for (int j = 0; j < b[i].size(); j++) {
                int y = 2 * j - last + wc, x = 2 * j - (b[i][j] - 1) + wc;
                // 查询 sum([1,t-1] 的权值和), 其中t在[x,y]范围内,
                ans += sum(y - 1) - (x >= 3 ? sum(x - 2) : 0);
                // [x,y] 这些数的权值+1
                add(x, 1, 2 * n + 1);
                add(y + 1, -1, 2 * n + 1);
                last = b[i][j];
            }
            last = 0;
            for (int j = 0; j < b[i].size(); j++) {
                int y = 2 * j - last + wc, x = 2 * j - (b[i][j] - 1) + wc;
                add(x, -1, 2 * n + 1);
                add(y + 1, 1, 2 * n + 1);
                last = b[i][j];
            }
        }
        printf("%lld\n", ans);
        return 0;
    }
    
  • 相关阅读:
    ActiveMQ基础教程JMS概述
    spring JMS在接收消息的时候总是报错
    java中实现同步的两种方式:syschronized和lock的区别和联系
    JMS之——ActiveMQ时抛出的错误Could not connect to broker URL-使用线程池解决高并发连接
    jQuery 实现 bootstrap 模态框 删除确认
    Jsp使用遍历List集合
    list里面放的实体对象,页面用c:foreach应该怎么取?
    如何停止处于stopping状态的windows服务(使用taskkill)
    Editplus配置Python的开发环境
    NAT对于网络上的其它人都不可见(但可以转发端口),Bridged和网络里的其它物理机没区别,Internal只能在虚拟机之间可见,Host-only只对主机可见(最符合我的服务器需求),最多可设置8块网卡实现混杂
  • 原文地址:https://www.cnblogs.com/dixiao/p/15671667.html
Copyright © 2020-2023  润新知