返回顶部

Note1

 

 

 

in & out

  • 读入输出优化
关闭输入输出流同步(调试时注释掉)

ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
读入大佬版

template<class T>inline void read(T &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9')  {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}//调用时直接int n; read(n);就好了
读入基础版

inline int read()
{
    int x=0,f=1;
    char ch;
    while(ch<'0'||ch>'9')  {if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return f*x;
}//调用  int x=read();
输出

inline void write(int x)
{
    int f=0;char ch[20];
    if(!x){puts("0");return;}
    if(x<0){putchar('-');x=-x;}
    while(x)ch[++f]=x%10+'0',x/=10;
    while(f)putchar(ch[f--]);
    putchar('\n');
}//调用   write(x);
View Code
  • 文件输入输出
   freopen("xxx.in","r",stdin);
        freopen("xxx.out","w",stdout);
        ...
         fclose(stdin);fclose(stdout);   
View Code

 

  • 输入到行末、文末
   输入n行,每行数量不定
     for(int i=1;i<=n;i++){
         char c=' ';
         while(c!='\n'){
         cin>>a[tot++];
            c=getchar();
           }
        }
   到文件结束
     while(scanf("%d",&a)==1)   //scanf返回值=输入元素数
     或者 while(cin>>a){} 
     或者 while(~scanf("%d",&a))
View Code

 


字符数组&字符串(用法)

  • 字符数组
    赋值 strcpy(s1,s2);
    长度 strlen(s);
    比较 strcmp(s1,s2);
    连接 strcat(s1,s2);
    查找字串 strstr(s1,s2); //返回s2在s1中的位置,找不到则返回NULL
View Code

 

  • 字符串(字符串排序用string)
    <,>, ==号都已重载,可以直接使用(字典序)
    添加 s+='a';
    长度 s.length();    
View Code

 


数据结构

· 单调栈

详解传送门
例题点这儿

例题 我的代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define M 81000
struct node{
    int v,x;
}t[M];
int a[M],n,cnt,pre[M],now;
ll ans;

int main(){
//    freopen("now.in","r",stdin);
    cin>>n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    t[++cnt].v=a[1];t[cnt].x=1;pre[1]=cnt;
    int i=2;now=1;
    while(i<=n){
        while(a[i]>=t[cnt].v&&cnt>=1){
            ans+=now-pre[t[cnt].x];
            cnt--;
        }
        t[++cnt].v=a[i];
        pre[i]=++now;
        t[cnt].x=i++;
    }
    while(cnt){
        ans+=now-pre[t[cnt--].x];
    }
    cout<<ans;
//    fclose(stdin);
}
View Code

 

· 单调队列

详解传送门
例题1点这儿
例题2点这儿,代码有注释

例题1 我的代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
#define M 1010000
struct node{
    int v,id;
}q[M];
int h,t,n,k,a[M],ans[M],cnt;

int main(){
//    freopen("testdata.in","r",stdin);
    cin>>n>>k;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    h=1;t=0;        //
    for(int i=1;i<=n;i++){
        while(h<=t&&i-q[h].id+1>k)h++;
        while(h<=t&&a[i]<=q[h].v)h++;
        while(h<=t&&a[i]<=q[t].v)t--;
        q[++t].v=a[i];q[t].id=i;
        if(i>=k)ans[++cnt]=q[h].v;
    }
    for(int i=1;i<=cnt;i++)cout<<ans[i]<<" ";cout<<endl;
    h=1;t=0;cnt=0;    //
    for(int i=1;i<=n;i++){
        while(i-q[h].id+1>k)h++;
        while(h<=t&&a[i]>=q[h].v)h++;
        while(h<=t&&a[i]>=q[t].v)t--;
        q[++t].v=a[i];q[t].id=i;
        if(i>=k)ans[++cnt]=q[h].v;
    }
    for(int i=1;i<=cnt;i++)cout<<ans[i]<<" ";
//    fclose(stdin);
}
例题一
 
例题2 我的代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define ll long long
#define M 2010000
int h,t,k,all;
struct node{
    int v,id;
}q[M];
int main(){
//    freopen("now.in","r",stdin);
    cin>>all;
    char c[10];
    int x;
    while(all--){                 //多组数据 
        h=1;t=0;k=0;int now=0;   //h队首,t队尾,k前面结束面试的人数,now面试人数统计 
        while(scanf("%s",c),c[0]!='E'){  //E为END 
            if(c[0]=='S')continue;else         //S为START 
            if(c[0]=='C'){                 //C为加入一个来面试的人 
                scanf("%s%d",c,&x);
                now++;                     //计数器+1 
                while(h<=t&&q[h].v<=x)h++;  //队首可维护性比x低的出队 
                while(h<=t&&q[t].v<=x)t--;  //队尾可维护性比x低的出队 
                q[++t].v=x;q[t].id=now;        // x入队,id记录入队的次序 
            }else
            if(c[0]=='G'){                //G尾排在前面的人结束面试离开 
                if(k<now)k++;            //计数 
                while(h<=t&&q[h].id<=k)h++;//如果队首入队的次序小于等于k,那么他就是结束面试离开了 
            }else
            if(c[0]=='Q'){                //Q为询问最大 
                if(h<=t)printf("%d\n",q[h]);//队列不为空 
                else printf("-1\n");    //队列为空 
            }else continue;
        }
    }
//    fclose(stdin);
}
例题二

 

 

· 堆+优先队列

  • STL(priority_queue)
include<queue>
include<vector>
①大根堆
priority_queue<int>h;   //默认大根堆
②小根堆
priority_queue<int,vector<int>,greater<int> >h;
③附加信息大根堆
#include<utility>
priority_queue<pair<int,node>,vector<pair<int node> > >h;
入堆
int a;node b;
h.push(make_pair(a,b));
出堆
pair<int,node>a;
a=h.top();h.pop();
调用时用a.first和a.second

empty()  如果队列为空,则返回真
pop()   删除对顶元素,删除第一个元素
push()  加入一个元素
size()   返回优先队列中拥有的元素个数
top()   返回优先队列对顶元素,返回优先队列中有最高优先级的元素
View Code

 

  • 自定义优先级:
struct cmp {     
  operator bool ()(int x, int y)     
  {        
     return x > y;   // x小的优先级高       
     //也可以写成其他方式,如: return p[x] > p[y];表示p[i]小的优先级高
  }
};
priority_queue<int, vector<int>, cmp> q;    //定义方法
//其中,第二个参数为容器类型。第三个参数为比较函数。
3、结构体声明方式:  ★★★自定义优先级用这个!

struct node {     
  int x, y;     
  friend bool operator < (node a, node b)     
  {         
    return a.x > b.x;    //结构体中,x小的优先级高     
  }
};
priority_queue<node>q;   //定义方法
//在该结构中,y为值, x为优先级。
//通过自定义operator<操作符来比较元素中的优先级。
//在重载”<”时,最好不要重载”>”,可能会发生编译错误
View Code

 

  • 非STL
#include<bits/stdc++.h> //小根堆 
using namespace std;

int heap[20050],cur;    //cur堆中元素数 

void insert(int val){}    //插入
    heap[++cur]=val;
    int t=cur;
    while(t>1){}         //新元素没成为树根时
        int root=t/2;   //找爸爸 
        if(heap[root]>val)swap(heap[root],heap[t]);  //交换 
            else break;
        t=root;            //变成爸爸 
    }
}
int pop(){     //删除(取数)
     if(cur==0)return -1; 
     int t=heap[1];   //保存根顶 
     heap[1]=heap[cur--];
     int root=1;
     while(2*root<=cur){}    //还没变成树叶
         int l=root*2,r=root*2+1;    //左右儿子 
         if(r>cur||heap[l]<heap[r])
             if(heap[root]>heap[l]{
                 swap(heap[root],heap[l]);
                 root=l;
             }else break;
         else
             if(heap[root]>heap[r]){
                 swap(heap[root],heap[r]);
                 root=r;
             }else break;
     }
     return t;
}
View Code

 

· ST表

静态RMQ,Onlogn建表,O1查询

const int N=100007;
int a[N],st[N][20];
void st_init(){//初始化
    for(int i=1;i<=n;i++)st[i][0]=a[i];
    for(int j=1;(1<<j)<=n;j++)
    for(int i=1;i+(1<<j)-1<=n;i++)
        st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
int st_query(int l,int r){//查询
    int k=log2(r-l+1);
    return max(st[l][k],st[r-(1<<k)+1][k]);
}
View Code

 

· 树状数组

相对于线段树的优点:省空间,常数小,速度快

—维护前缀和
—单点修改,区间求和
—区间修改(维护差分数组前缀和)+单点查询
—可以解决逆序对

int n;
int a[1005],c[1005]; //对应原数组和树状数组

int lowbit(int x){        //    找x二进制最低位的1对应的值
    return x&(-x);
}

void updata(int i,int k){    //在i位置加上k
    while(i <= n){
        c[i] += k;
        i += lowbit(i);
    }
}

int getsum(int i){        //求A[1 - i]的和
    int ans = 0;
    while(i > 0){
        ans += c[i];
        i -= lowbit(i);
    }
    return ans;
}
View Code

 

· 线段树

—单点修改、区间修改、区间查询
模板题传送门

涉及操作:1.区间修改,把区间每个数修改为val
		(3.单点修改(可以套区间修改的函数modify(p,p,1,n,1,val)) 
		 3.区间求和
#define ll long long
#define M 101000
int t[M*4],lazy[M*4],n;//存树和lazy的数组要开4倍的MAXN
void push_up(int k){    //状态往上更新合并
    t[k]=t[k<<1]+t[k<<1|1];
}
void push_down(int k,int l,int r){    //下放lazy标记
    if(lazy[k]==0)return;
    int m=(l+r)>>1;
    lazy[k<<1]=lazy[k<<1|1]=lazy[k];
    t[k<<1]=(m-l+1)*lazy[k];
    t[k<<1|1]=(r-m)*lazy[k];
    lazy[k]=0;
}

void build(int l,int r,int k){    //建树
    if(l==r){
        t[k]=1;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    push_up(k);
}
void updata(int p,int l,int r,int k,int val){    //单点修改(+、-)
    if(l==r){
        tr[k]+=val;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid)updata(p,l,mid,k<<1,val);
    else updata(p,mid+1,r,k<<1|1,val);
    push_up(k);
}
void modify(int l_,int r_,int l,int r,int k,int val){ //区间修改(+、-)
    if(l_<=l&&r_>=r){
        lazy[k]=val;
        t[k]=(r-l+1)*val;
        return;
    }
    int mid=(l+r)>>1;
    push_down(k,l,r);
    if(l_<=mid)modify(l_,r_,l,mid,k<<1,val);
    if(r_>mid)modify(l_,r_,mid+1,r,k<<1|1,val);
    push_up(k);
}
int query(int l_,int r_,int l,int r,int k){    //区间查询
    if(l_<=l&&r_>=r)return t[k];
    int mid=(l+r)>>1;
    push_down(k,l,r);
    int s=0;
    if(l_<=mid)s+=query(l_,r_,l,mid,k<<1);
    if(r_>mid)s+=query(l_,r_,mid+1,r,k<<1|1);
    return s;
}
View Code

 

----区间加减+区间乘法+区间求和
模板题传送门

涉及操作:1.区间乘法,把区间每个数乘val
		 2.区间加减,把区间每个数加减val
		 3.区间求和
思路,开两个lazy数组,打乘法标记时,把当前点的加法标记也乘上val。push_down操作时先乘后加即可(因为加法是已经乘上了乘法标记的)
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100007
#define ll long long

ll n,m,a[MAXN];
ll t[MAXN*4],lazy[MAXN*4],p,lazy2[MAXN*4];//lazy是加法懒标记,lazy2是乘法懒标记
template<class T>void read(T &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9')  {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}    //快读
void push_up(int k){
    t[k]=(t[k<<1]+t[k<<1|1])%p;
}    向上更新区间和
void push_plus(int k,int l,int r){
    if(l==r||lazy[k]==0)return;
    lazy[k<<1]=(lazy[k<<1]+lazy[k])%p;
    lazy[k<<1|1]=(lazy[k<<1|1]+lazy[k])%p;
    int md=(l+r)>>1;
    t[k<<1]=(t[k<<1]+lazy[k]*(md-l+1)%p)%p;
    t[k<<1|1]=(t[k<<1|1]+lazy[k]*(r-md)%p)%p;
    lazy[k]=0;
}//下放加法懒标记    
void push_multi(int k,int l,int r){
    if(l==r||lazy2[k]==1)return;
    lazy[k<<1]=lazy[k<<1]*lazy2[k]%p;
    lazy[k<<1|1]=lazy[k<<1|1]*lazy2[k]%p;
    lazy2[k<<1]=lazy2[k<<1]*lazy2[k]%p;
    lazy2[k<<1|1]=lazy2[k<<1|1]*lazy2[k]%p;
    int md=(l+r)>>1;
    t[k<<1]=t[k<<1]*lazy2[k]%p;
    t[k<<1|1]=t[k<<1|1]*lazy2[k]%p;
    lazy2[k]=1;
}//下放乘法懒标记(对应点的加法懒标记同时也乘上val)

void build(int l,int r,int k){
    if(l==r){
        t[k]=a[l]%p;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,k<<1);
    build(mid+1,r,k<<1|1);
    push_up(k);
}//建树
void updata_plus(int l_,int r_,int l,int r,int k,int val){
    if(l_<=l&&r_>=r){
        lazy[k]=(lazy[k]+val)%p;
        t[k]=(t[k]+(r-l+1)*val%p)%p;
        return;
    }
    int mid=(l+r)>>1;
    push_multi(k,l,r);
    push_plus(k,l,r);//先乘后加
    if(l_<=mid)updata_plus(l_,r_,l,mid,k<<1,val);
    if(r_>mid)updata_plus(l_,r_,mid+1,r,k<<1|1,val);
    push_up(k);
}//区间加减
void updata_multi(int l_,int r_,int l,int r,int k,int val){
    if(l_<=l&&r_>=r){
        lazy[k]=lazy[k]*val%p;//加法标记同时也乘val
        lazy2[k]=lazy2[k]*val%p;
        t[k]=t[k]*val%p;
        return;
    }
    int mid=(l+r)>>1;
    push_multi(k,l,r);
    push_plus(k,l,r);
    if(l_<=mid)updata_multi(l_,r_,l,mid,k<<1,val);
    if(r_>mid)updata_multi(l_,r_,mid+1,r,k<<1|1,val);
    push_up(k);
}//区间乘法
ll query(int l_,int r_,int l,int r,int k){
    if(l_<=l&&r_>=r)return t[k]%p;
    int mid=(l+r)>>1;
    ll sum=0;
    push_multi(k,l,r);
    push_plus(k,l,r);
    if(l_<=mid)sum=(sum+query(l_,r_,l,mid,k<<1))%p;
    if(r_>mid)sum=(sum+query(l_,r_,mid+1,r,k<<1|1))%p;
    return sum;
}
int main(){
    cin>>n>>m>>p;
    for(int i=1;i<=n;i++)read(a[i]);
    for(int i=1;i<=MAXN*4-1;i++)lazy2[i]=1;
    build(1,n,1);
    int b,c,d,e;
    for(int i=1;i<=m;i++){
         read(b);
         if(b==1){//乘法
             read(c);read(d);read(e);
             updata_multi(c,d,1,n,1,e);
         }else
         if(b==2){//加法
             read(c);read(d);read(e);
             updata_plus(c,d,1,n,1,e);
         }else{//求和
             read(c);read(d);
             printf("%lld\n",query(c,d,1,n,1));
         }
    }
}
View Code

 

· 分块

xjb更新,xjb查询就用分块 Ovo , 时间复杂度是加一个√n

!丧心病狂的出题人可  能会卡√n ,这时候可以用√n +1√n -1√(n/lgn)

Loj分块入门1~9题传送门
上题hzwer学长的详解链接我的题解链接

模板涉及操作: 1.单点加减
	     2.区间加减
               3.区间求和
#define maxn 500007
typedef long long ll;

int n,m,size,cnt,l[maxn],r[maxn],belong[maxn];
ll v[maxn],a[maxn],lazy[maxn];
//l,r是第i块的左右端点,belong记录i点属于哪个块
//size是块的大小,cnt是块的数量,v是块维护的值

void build(){    //划分建块 
    size=sqrt(n); 
    cnt=n/size;if(n%size)cnt++;//设定块的大小和数量 
    for(int i=1;i<=cnt;i++)        //记录每个块的左右端点 
        l[i]=(i-1)*size+1,r[i]=i*size;
    r[cnt]=n;
    for(int i=1;i<=n;i++)        //记录每个点属于哪个块 
        belong[i]=(i-1)/size+1;
    for(int i=1;i<=cnt;i++)        //初始化 
        for(int j=l[i];j<=r[i];j++)
            v[i]+=a[j];
}
inline void plus(int x,int val){//单点加val 
    a[x]+=val;
    v[belong[x]]+=val;
}
inline void add(int L,int R,ll c){//区间加val
    if(belong[L]==belong[R]){
        for(int i=L;i<=R;i++)a[i]+=c,v[belong[i]]+=c;
        return;
    }
    for(int i=L;i<=r[belong[L]];i++)a[i]+=c,v[belong[i]]+=c;
    for(int i=belong[L]+1;i<belong[R];i++)lazy[i]+=c;
    for(int i=l[belong[R]];i<=R;i++)a[i]+=c,v[belong[i]]+=c;
}
inline ll query(int L,int R,ll c){//区间求和(mod c)
    ll ans=0;
    if(belong[L]==belong[R]){
        for(int i=L;i<=R;i++)ans=(ans+a[i]+lazy[belong[i]])%c;
        return ans;
    }
    for(int i=L;i<=r[belong[L]];i++)ans=(ans+a[i]+lazy[belong[i]])%c;
    for(int i=belong[L]+1;i<belong[R];i++)ans=(ans+v[i]+lazy[i]*(r[i]-l[i]+1))%c;
    for(int i=l[belong[R]];i<=R;i++)ans=(ans+a[i]+lazy[belong[i]])%c;
    return ans;
}
//inline ll query_(int l_,int r_){//没有lazy数组的区间求和 
//    ll ans=0;
//    if(belong[l_]==belong[r_]){//在同一个块内 
//        for(int i=l_;i<=r_;i++)ans+=a[i];
//        return ans;
//    }
//    for(int i=l_;i<=r[belong[l_]];i++)
//        ans+=a[i];    //左端点非整体块暴力 
//    for(int i=belong[l_]+1;i<belong[r_];i++)
//        ans+=v[i];    //中间整体快累加 
//    for(int i=l[belong[r_]];i<=r_;i++)
//        ans+=a[i];    //右端点非整体块暴力 
//    return ans;
//}
View Code

 

分块练习2,涉及操作:区间加减,求区间内小于k的元素个数。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=50007;
template<class T>inline void read(T &x){
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}
int n,size,cnt,l[N],r[N],belong[N];
int a[N],lazy[N];
vector<int>vec[505];//块内排序 
void build(){
    size=sqrt(n);
    cnt=n/size;if(n%size)cnt++;
    for(int i=1;i<=cnt;i++)
        l[i]=(i-1)*size+1,r[i]=i*size;
    r[cnt]=n;
    for(int i=1;i<=n;i++){
        belong[i]=(i-1)/size+1;
        vec[belong[i]].push_back(a[i]);
    }
    for(int i=1;i<=cnt;i++)
        sort(vec[i].begin(),vec[i].end());
}
void reset(int x){//重新排序 
    vec[x].clear();
    for(int i=l[x];i<=r[x];i++)
        vec[x].push_back(a[i]);
    sort(vec[x].begin(),vec[x].end());
}
void add(int L,int R,int c){
    if(belong[L]==belong[R]){
        for(int i=L;i<=R;i++)a[i]+=c;
        reset(belong[L]);
        return;
    }
    for(int i=L;i<=r[belong[L]];i++)a[i]+=c;
    reset(belong[L]);
    for(int i=belong[L]+1;i<belong[R];i++)lazy[i]+=c;
    for(int i=l[belong[R]];i<=R;i++)a[i]+=c;
    reset(belong[R]);
}
int query(int L,int R,int c){
    int ans=0;
    if(belong[L]==belong[R]){
        for(int i=L;i<=R;i++)
            if(a[i]+lazy[belong[i]]<c)ans++;
        return ans;
    }
    for(int i=L;i<=r[belong[L]];i++)
        if(a[i]+lazy[belong[i]]<c)ans++;
    for(int i=belong[L]+1;i<belong[R];i++){
        int x=c-lazy[i];
        ans+=lower_bound(vec[i].begin(),vec[i].end(),x)-vec[i].begin();
    }
    for(int i=l[belong[R]];i<=R;i++)
        if(a[i]+lazy[belong[i]]<c)ans++;
    return ans;
}    
int main(){
    cin>>n;
    for(int i=1;i<=n;i++)read(a[i]);
    build();
    int opt,l,r,c;
    for(int i=1;i<=n;i++){
        read(opt);read(l);read(r);read(c);
        if(opt==0)add(l,r,c);
        else printf("%d\n",query(l,r,c*c));
    }
}
View Code

 

· 珂朵莉树(模板)

操作随机的话复杂度接近O(mlogn)

----> 例题1(生成随机数)传送门
----> 题解1传送门

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
#define IT set<node>::iterator 
const int MAXN=1e5+7;
const int MOD7=1e9+7;
struct node{
    int l,r;
    mutable LL v;
    node(int L,int R=-1,LL V=0):l(L),r(R),v(V){}
    bool operator<(const node &o)const{
        return l<o.l;
    }
};
LL qpow(LL a,LL b,LL mod){//快速幂 
    LL ans=1;
    LL x=a%mod;
    while(b){
        if(b&1)ans=ans*x%mod;
        x=x*x%mod;
        b>>=1;
    }
    return ans;
}
set<node>s;
IT split(int pos){
    IT it=s.lower_bound(node(pos));
    if(it!=s.end()&&it->l==pos)return it;
    --it;
    int L=it->l,R=it->r;
    LL V=it->v;
    s.erase(it);
    s.insert(node(L,pos-1,V));
    return s.insert(node(pos,R,V)).first;
}
void add(int l,int r,LL val){//给l到r所有数加上val 
    IT itr=split(r+1),itl=split(l);
    for(;itl!=itr;++itl)
        itl->v+=val;
}
void assign_val(int l,int r,LL val){//把l到r所有数改为val 
    IT itr=split(r+1),itl=split(l);
    s.erase(itl,itr);
    s.insert(node(l,r,val));
}
LL ranks(int l,int r,int k){//询问l到r区间第k小 
    vector<pair<LL,int> >vp;
    IT itr=split(r+1),itl=split(l);
    vp.clear();
    for(;itl!=itr;++itl)
        vp.push_back(pair<LL,int>(itl->v,itl->r - itl->l +1));
    sort(vp.begin(),vp.end());
    for(vector<pair<LL,int> >::iterator it=vp.begin();it!=vp.end();++it){
        k-=it->second;
        if(k<=0)return it->first;
    }
}
LL sum(int l,int r,int ex,int mod){//询问l到r每个数字的x次方模y的和 
    IT itr=split(r+1),itl=split(l);
    LL res=0;
    for(;itl!=itr;++itl)
        res=(res+(LL)(itl->r - itl->l+1)*qpow(itl->v,LL(ex),LL(mod))) %mod;
    return res;
}
int n,m;
LL seed,vmax;
LL rd(){
    LL ret=seed;
    seed=(seed*7+13)%MOD7;
    return ret;
}
LL a[MAXN];
int main(){
    cin>>n>>m>>seed>>vmax;
    for(int i=1;i<=n;i++){
        a[i]=(rd()%vmax)+1;
        s.insert(node(i,i,a[i]));
    }
    s.insert(node(n+1,n+1,0));
    int lines=0;
    for(int i=1;i<=m;i++){
        //----------------------------- 
        int op=int(rd()%4)+1;
        int l=int(rd()%n)+1;
        int r=int(rd()%n)+1;
        if(l>r)swap(l,r);
        int x,y;
        if(op==3)x=int(rd()%(r-l+1))+1;
        else x=int(rd()%vmax)+1;
        if(op==4)y=int(rd()%vmax)+1;
        //------------------------------以上为题目要求生成数据 
        
        if(op==1)add(l,r,LL(x));
        else if(op==2)assign_val(l,r,LL(x));
        else if(op==3)cout<<ranks(l,r,x)<<endl;
        else cout<<sum(l,r,x,y)<<endl;
    }
    return 0;
}
View Code

 

---->例题2(给定每次操作)传送门

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<string.h>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
#define IT set<node>::iterator 
struct node{
    int l,r;
    mutable LL v;
    node(int L,int R=-1,LL V=0):l(L),r(R),v(V){}
    bool operator<(const node &o)const{
        return l<o.l;
    }
};
LL qpow(LL a,LL b,LL mod){//快速幂 
    LL ans=1;
    LL x=a%mod;
    while(b){
        if(b&1)ans=ans*x%mod;
        x=x*x%mod;
        b>>=1;
    }
    return ans;
}
set<node>s;
IT split(int pos){
    IT it=s.lower_bound(node(pos));
    if(it!=s.end()&&it->l==pos)return it;
    --it;
    int L=it->l,R=it->r;
    LL V=it->v;
    s.erase(it);
    s.insert(node(L,pos-1,V));
    return s.insert(node(pos,R,V)).first;
}
void add(int l,int r,LL val){//给l到r所有数加上val 
    IT itr=split(r+1),itl=split(l);
    for(;itl!=itr;++itl)
        itl->v=(itl->v+val)%10007;
}
void muti(int l,int r,LL val){//给l到r所有数乘上val 
    IT itr=split(r+1),itl=split(l);
    for(;itl!=itr;++itl)
        itl->v=(itl->v*val)%10007;
}
void assign_val(int l,int r,LL val){//把l到r所有数改为val 
    IT itr=split(r+1),itl=split(l);
    s.erase(itl,itr);
    s.insert(node(l,r,val));
}
LL sum(int l,int r,int ex){//询问l到r每个数字的x次方和 
    IT itr=split(r+1),itl=split(l);
    LL res=0;
    for(;itl!=itr;++itl)
        res=(res+(long long)(itl->r - itl->l+1)*qpow(itl->v,(long long)ex,10007))%10007;
    return res;
}
int n,m;
int main(){
    while(cin>>n>>m,n!=0||m!=0){
        s.clear();
        for(int i=1;i<=n+1;i++)s.insert(node(i,i,0));
        int opt,x,y;
        long long z;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d%lld",&opt,&x,&y,&z);
            if(opt==1)add(x,y,z);else
            if(opt==2)muti(x,y,z);else
            if(opt==3)assign_val(x,y,z);else
            printf("%lld\n",sum(x,y,z));
        }
    }
    return 0;
}
View Code

 


高精度

重载,+ ,- ,* , cin,cout, 比较大小

#include<cstdio>
#include<cstring> 
#include<iostream>
using namespace std;
 
const int maxn=200;
struct bign{
  int len,s[maxn];
  bign() {
    memset(s,0,sizeof(s));
    len=1;
  }
  bign(int num) {
    *this=num;
  }
  bign(const char* num){
    *this=num;
  }
  bign operator = (int num){
    char s[maxn];
    sprintf(s,"%d",num);
    *this=s;
    return *this;
  } 
  string str()const{
    string res="";
    for(int i=0;i<len;i++)res=(char)(s[i]+'0')+res;
    if(res=="")res="0";
    return res;
  }
  void clean(){
    while(len>1&&!s[len-1])len--;
  }
  bign operator = (const char* num){
    len=strlen(num);
    for(int i=0;i<len;i++)s[i]=num[len-i-1]-'0';
    return *this;
  }
  bign operator + (const bign& b)const{
    bign c;
    c.len=0;
    for(int i=0,g=0;g||i<max(len,b.len);i++){
      int x=g;
      if(i<len)x+=s[i];
      if(i<b.len)x+=b.s[i];
      c.s[c.len++]=x%10;
      g=x/10;
    }
    return c;
  }
  bign operator * (const bign& b){
    bign c; c.len=len+b.len;
    for(int i=0;i<len;i++)
      for(int j =0;j<b.len;j++)
        c.s[i+j]+=s[i]*b.s[j];
    for(int i=0;i<c.len-1;i++){
      c.s[i+1]+=c.s[i]/10;
      c.s[i]%=10;
    }
    c.clean();
    return c;
  }
  bign operator - (const bign& b){
    bign c; c.len = 0;
    for(int i=0,g=0;i<len;i++){
      int x=s[i]-g;
      if(i<b.len)x-=b.s[i];
      if(x>=0)g=0;
      else {
        g=1;
        x+=10;
      }
      c.s[c.len++]=x;
    }
    c.clean();
    return c;
  }
  bool operator < (const bign& b)const{
    if(len!=b.len)return len<b.len;
    for(int i=len-1;i>=0;i--)
      if(s[i]!=b.s[i])return s[i]<b.s[i];
    return false;
  }
  bool operator > (const bign& b) const{
    return b<*this;
  }
  bool operator <= (const bign& b){
    return !(b>*this);
  }
  bool operator == (const bign& b){
    return !(b<*this)&&!(*this<b);
  }
  bign operator += (const bign& b){
    *this=*this+b;
    return *this;
  }
};
istream& operator >> (istream &in,bign& x) {
  string s;
  in>>s;
  x=s.c_str();
  return in;
}
ostream& operator << (ostream &out,const bign& x) {
  out<<x.str();
  return out;
}

int main() {
  bign a;
  cin>>a;
  a +="123456789123456789000000000";
  cout<<a*2<<endl;
  return 0;
}
View Code

 

map、set、vecotr、deque

C++11中,容器内元素可以用
for(auto &i:a)遍历 //加&是引用(可以修改值),不加只能访问,不能修改
注意,低于c++11的版本需要在编译选项里加上 -std=c++11这句话

· deque

详解链接

· map

(map是用R-B tree写的,存储按key排序,操作时间复杂度大都是logn)
map的键和值是唯一的,而如果一个键需要对应多个值,就只能用multimap

1.定义
map<type1,type2>mp;   //type1是key  type2是value

2.map容器内元素的访问
①通过下标访问
注意:map的键是唯一的
mp['c']=20;
②通过迭代器访问
定义方式与其他STL容器迭代器相同:
map<type1,type2>::iterator it=mp.find(...);
it->fitst对应key,it->second对应value

3.map常用函数
①插入insert
// 第一种 用insert函數插入pair(已出现的不能覆盖)
mapStudent.insert(pair<int, string>(000, "student_zero"));
// 第二种 用insert函数插入value_type数据(已出现的不能覆盖)
mapStudent.insert(map<int, string>::value_type(001, "student_one"));
// 第三种 用"array"方式插入(可覆盖已出现的)
mapStudent[123] = "student_first";
mapStudent[456] = "student_second";
②查找
// find 返回迭代器指向当前查找元素的位置否则返回map::end()位置
map<type1,type2>::iterator iter = mapStudent.find("123");
 if(iter != mapStudent.end())
    cout<<"Find, the value is"<<iter->second<<endl;
 else
       cout<<"Do not Find"<<endl;
④删除
//迭代器刪除
iter = mapStudent.find("123");
mapStudent.erase(iter);
 //用关键字刪除
int n = mapStudent.erase("123"); //如果刪除了會返回1,否則返回0
 //用迭代器范围刪除 : 把整个map清空
mapStudent.erase(mapStudent.begin(), mapStudent.end());
//等同于mapStudent.clear()
⑤大小
int nSize = mapStudent.size();

4.所有函数
     begin()         返回指向map头部的迭代器
     clear()        删除所有元素
     count()         返回指定元素出现的次数
     empty()         如果map为空则返回true
     end()           返回指向map末尾的迭代器
     equal_range()   返回特殊条目的迭代器对
     erase()         删除一个元素
     find()          查找一个元素
     get_allocator() 返回map的配置器
     insert()        插入元素
     key_comp()      返回比较元素key的函数
     lower_bound()   返回键值>=给定元素的第一个位置
     max_size()      返回可以容纳的最大元素个数
     rbegin()        返回一个指向map尾部的逆向迭代器
     rend()          返回一个指向map头部的逆向迭代器
     size()          返回map中元素的个数
     swap()           交换两个map
     upper_bound()    返回键值>给定元素的第一个位置
     value_comp()     返回比较元素value的函数
View Code

 

· set

1、set中的元素都是排好序的
2、set集合中没有重复的元素
3、set中数元素的值不能直接被改变

迭代器 set<int>iterator:: it=
insert()        插入
lower_bound()   返回值>=给定元素的第一个位置
upper_bound()    返回值>给定元素的第一个位置
begin()        返回set容器第一个元素的迭代器
end()      返回一个指向当前set末尾元素的下一位置的迭代器.
clear()          删除set容器中的所有的元素
empty()    判断set容器是否为空
size()      返回当前set容器中的元素个数
View Code

 


posted @ 2019-09-07 18:34  晚樱  阅读(11)  评论(0)    收藏  举报