zoukankan      html  css  js  c++  java
  • 【日记】 12.5

    12.5日记

    线段树

    1. OpenJ2528:画板长度1-10000000,依次贴了n<=1e4张海报,问最后有几张不同的画板露了出来。

    思路:区间修改,最后暴力单点查询,直接把v数组当lazy用即可。还是记住,下传之后自己必须清零,否则会出问题。最后用unordered_set去重即可。不知道为什么开4*1e4会RE……开1e5就好了。

    #include<bits/stdc++.h>
    using namespace std;
    #define mid (l+r)/2
    const int M=1e5+20;
    int v[M*4],l[M],r[M];
    vector<int> a;
    unordered_map<int,int> rev;
    unordered_set<int> st;
    inline void push_down(int id,int l,int r){
    	if (v[id])
        	v[id*2]=v[id*2+1]=v[id],v[id]=0;
    }
    void build(int id,int l,int r){
        v[id]=0;
        if (l==r)
            return;
        build(id*2,l,mid);
        build(id*2+1,mid+1,r);
    }
    void operate(int id,int l,int r,int ql,int qr,int x){
        if (ql<=l&&r<=qr){
            v[id]=x;
            return;
        }
        push_down(id,l,r);
        if (ql<=mid)
            operate(id*2,l,mid,ql,qr,x);
        if (mid<qr)
            operate(id*2+1,mid+1,r,ql,qr,x);
    }
    int query(int id,int l,int r,int pos){
    	if (l==r)
    		return v[id];
    	push_down(id,l,r);
    	if (pos<=mid)
    		return query(id*2,l,mid,pos);
    	else
    		return query(id*2+1,mid+1,r,pos);
    }
    int main(){
        int T;
        scanf("%d",&T);
        for(int z=1;z<=T;++z){
            int n;
            scanf("%d",&n);
            for(int i=1;i<=n;++i)
                scanf("%d%d",&l[i],&r[i]),a.push_back(l[i]),a.push_back(r[i]);
            sort(a.begin(),a.end());
            int len=unique(a.begin(),a.end())-a.begin();
            for(int i=0;i<len;++i)
                rev[a[i]]=i+1;
            build(1,1,len);
            for(int i=1;i<=n;++i)
                operate(1,1,len,rev[l[i]],rev[r[i]],i);
            for(int i=1;i<=len;++i)
                st.insert(query(1,1,len,i));
            printf("%d
    ",st.size());
            a.clear(),st.clear();
        }
        return 0;
    }
    
    1. HDU1540:给n个点,每个点和相邻的点有地道相连。三个操作,1,炸毁某个点和其相邻的地道。2,修好上一个被炸毁的点和地道。3,询问某个点所在连通块的大小。

    思路:不知道这个题和线段树有什么关系……用set做就好了。set里存被炸毁的点。对于操作1直接insert。对于操作3,每个insert之后加入一个stack里,每次操作3就取stack栈顶元素再erase。对于操作2(假设询问x),如果x在集合里,输出0。否则找到集合里比他大和比他小的元素(就是相邻最接近的被炸毁的点),相减就是连通块大小,注意处理边界情况。然后就切了,比较好写。

    #include<bits/stdc++.h>
    using namespace std;
    const int M=5e4+20;
    set<int> st;
    stack<int> sta;
    int main(){
        int n,m;
        while(~scanf("%d%d",&n,&m)){
        	st.clear();
        	while(!sta.empty())
        		sta.pop();
    	    for(int i=1;i<=m;++i){
    	        char s[2];
    	        int x;
    	        scanf("%s",s);
    	        if (s[0]=='D')
    	            scanf("%d",&x),st.insert(x),sta.push(x);
    	        else if (s[0]=='Q'){
    	            scanf("%d",&x);
    	            if (st.count(x))
    	                printf("0
    ");
    	            else{
    	                set<int>::iterator it=st.lower_bound(x),itl=it;
    	                int lef,rt;
    	                if (it==st.begin())
    	                    lef=1;
    	                else
    	                    lef=*(--itl)+1;
    	                if (it==st.end())
    	                    rt=n;
    	                else
    	                    rt=*it-1;
    	                printf("%d
    ",rt-lef+1);
    	            }
    	        }
    	        else
    	            st.erase(sta.top()),sta.pop();
    	    }
    	}
        return 0;
    }
    
    

    单调数据结构

    1. HDU6319:询问每个[i,i+m-1]区间内,最大值和从i到最大值的最长严格上升子序列长度。

    思路:首先根据滑动窗口想到单调队列。如果从左往右,那么最大值是可以一次性求出来的,问题在于最长严格上升子序列的长度。实际上这道题应该从后往前扫,这样可以保证右端点截止在最大值,左端点一定包含第i个数。

    另外这题卡常,如果用stl的deque的话可能会T。不过最后我这份代码过了,只要取模部分注意一下即可。

    我吐了,少了个取模快了2s。

    另外,亲测register无用。

    #include<bits/stdc++.h>
    using namespace std;
    #define LL long long
    const int M=1e7+20;
    int a[M];
    deque<int> qu;
    int main(){
        int T;
        scanf("%d",&T);
        for(int z=1;z<=T;++z){
            int n,m,k,p,q,r,mod;
            LL A=0,B=0;
            scanf("%d%d%d%d%d%d%d",&n,&m,&k,&p,&q,&r,&mod);
            for(int i=1;i<=k;++i)
                scanf("%d",&a[i]);
            for(int i=k+1;i<=n;++i)
                a[i]=(1LL*p*a[i-1]+1LL*q*i+r)%mod;
            for(int i=n;i>=n-m+2;--i){
                while(!qu.empty()&&a[i]>=a[qu.front()])
                    qu.pop_front();
                qu.push_front(i);
            }
            for(int i=n-m+1;i>=1;--i){
                if (qu.back()-i+1>m)
                    qu.pop_back();
                while(!qu.empty()&&a[i]>=a[qu.front()])
                    qu.pop_front();
                qu.push_front(i),A+=a[qu.back()]^i,B+=qu.size()^i;
            }
            printf("%lld %lld
    ",A,B),qu.clear();
        }
        return 0;
    }
    
    
  • 相关阅读:
    VS2010安装笔记
    Blend4中文版中截取图片的方法
    改变窗口的位置 (转载)
    窗口的位置
    windows消息大全
    WM_MOUSELEAVE和WM_MOUSEHOVER使用
    setwindowpos
    无注册表的COM调用
    WM_CLOSE WM_QUIT WM_DESTROY 三者的区别
    WM_MOUSEWHEEL消息
  • 原文地址:https://www.cnblogs.com/diorvh/p/11993370.html
Copyright © 2011-2022 走看看