【日记】 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\n",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\n");
                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\n",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\n",A,B),qu.clear();
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/diorvh/p/11993370.html
今日推荐