2022/2/10

142 篇文章 1 订阅
92 篇文章 0 订阅

p6225 位运算+树状数组

通过这题发现异或大概是满足交换和结合律的,然后就可以发现规律了

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007,Log = 22;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(int a,int b){return a>b;}
ll n,q,a[200005],x,y,op;
struct ora{
    ll bit[200005];
    void add(ll x,ll y){
        for(int i=x;i<=n;i+=lowbit(i))
            bit[i]^=y;
    }
    ll ask(ll x){
        ll res=0;
        for(int i=x;i;i-=lowbit(i))
            res^=bit[i];
        return res;
    }
}t[2];
int main(){
    //freopen("in.txt","r",stdin);
    cin>>n>>q;
    for(int i=1;i<=n;i++) cin>>a[i],t[i&1].add(i,a[i]);
    while(q--){
        cin>>op>>x>>y;
        if(op==1){
            t[x&1].add(x,a[x]^y);a[x]=y;
        }
        else{
            if((x+y)&1) cout<<0<<endl;
            else cout<<(t[x&1].ask(y)^t[x&1].ask(x-1))<<endl;
        }
    }
    return 0;
}

p6278 树状数组+逆序对

可以看出,a[i1],a[i2]为逆序对,当a[i2]>=j时,这个逆序对就被摧毁了,当a[i2]<j时,以a[i2]为较小值的逆序对不会改变,所以我们可以求出每个a[i]以自己为较小值组成的逆序对的个数,然后遍历j(0~n-1),假如数组中有等于j的那就加上以j为较小值的逆序对个数,就是下一个j的答案

P6278 [USACO20OPEN]Haircut G题解 - 漂洋过海的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007,Log = 22;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(int a,int b){return a>b;}
ll n,t[100005];
struct sb{
    ll id,v;
}a[100005];
bool cmp(sb a,sb b){
    if(a.v==b.v) return a.id<b.id;
    return a.v<b.v;
}
void add(ll x,ll y){
    for(int i=x;i<=n;i+=lowbit(i))
    t[i]+=y;
}
ll ask(ll x){
    ll res=0;
    for(int i=x;i;i-=lowbit(i))
        res+=t[i];
    return res;
}
int main(){
    //freopen("in.txt","r",stdin);
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i].v,a[i].id=i,add(a[i].id,1);
    sort(a+1,a+n+1,cmp);
    ll ans=0;
    for(int j=0,i=1;j<n;j++){
            cout<<ans<<endl;
        while(i<=n&&a[i].v==j){
            ans+=ask(a[i].id-1);
            //cout<<ask(a[i].id-1)<<endl;
            add(a[i].id,-1);
            i++;
        }
    }
    return 0;
}

p6492 线段树左右区间前缀问题

这篇题解写的非常之叼哉

题解P6492 [COCI2010-2011#6] STEP - 暗ざ之殇 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007,N = 200005;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(int a,int b){return a>b;}
ll n,m,S[N<<2],H[N<<2],L[N<<2],R[N<<2],len[N<<2],ans[N<<2];
void work(ll p,ll k){
    ans[p]=S[p]=H[p]=1;
    L[p]=R[p]=k;
}
void pushup(ll p){
    if(R[p<<1]^L[p<<1|1]){
        ans[p]=H[p<<1]+S[p<<1|1];
        ans[p]=max(ans[p],ans[p<<1]);
        ans[p]=max(ans[p],ans[p<<1|1]);
    }
    else ans[p]=max(ans[p<<1],ans[p<<1|1]);
    L[p]=L[p<<1];R[p]=R[p<<1|1];
    if(S[p<<1]==len[p<<1]&&R[p<<1]^L[p<<1|1]) S[p]=S[p<<1]+S[p<<1|1];
    else S[p]=S[p<<1];
    if(H[p<<1|1]==len[p<<1|1]&&R[p<<1]^L[p<<1|1]) H[p]=H[p<<1|1]+H[p<<1];
    else H[p]=H[p<<1|1];
}
void build(ll l,ll r,ll p){
    len[p]=r-l+1;
    if(l==r){
        work(p,0);
        return;
    }
    ll m=l+r>>1;
    build(l,m,p<<1);
    build(m+1,r,p<<1|1);
    pushup(p);
}
void update(ll x,ll l,ll r,ll p){
    if(l==r){
        work(p,!L[p]);
        return;
    }
    ll m=l+r>>1;
    if(x<=m) update(x,l,m,p<<1);
    else update(x,m+1,r,p<<1|1);
    pushup(p);
}
int main(){
   // freopen("in.txt","r",stdin);
    cin>>n>>m;
    build(1,n,1);
    for(int i=1;i<=m;i++){

        int x;
        cin>>x;
        update(x,1,n,1);
        cout<<ans[1]<<endl;
    }
    return 0;
}

p1725 dp+单调队列优化

状态方程 dp[i]=max(dp[j](i-r<=j<=i-l))+a[i];但由于数据规模就需要单调队列优化,直接找到所求区间的最大值

题解 P1725 【琪露诺】 - skyshow 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007,N = 200005;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(int a,int b){return a>b;}
ll n,a[N],dp[N],l,r;
deque<ll>q;
int main(){
    //freopen("in.txt","r",stdin);
    n=read();l=read();r=read();
    for(int i=1;i<=n+1;i++) a[i]=read();
    memset(dp,-inf,sizeof(dp));
    dp[1]=0;
    ll ans=-inf;
    ll p=1;
    for(int i=l+1;i<=n+1;i++){
        while(!q.empty()&&dp[q.back()]<=dp[p]) q.pop_back();
        q.push_back(p);
        while(q.front()+r<i) q.pop_front();
        dp[i]=dp[q.front()]+a[i];
        p++;
    }
    for(int i=n-r+2;i<=n+1;i++) ans=max(ans,dp[i]);
    cout<<ans<<endl;
    return 0;
}

p6510 单调栈

设两个,一个维护A,另一个维护B,然后枚举B的值,二分查找A的下标

题解 P6510 【奶牛排队】 - 一扶苏一 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007,N = 200005;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(int a,int b){return a>b;}
ll n,a[100005],mn[100005],mx[100005],ans=0;
int main(){
   // freopen("in.txt","r",stdin);
    n=read();
    ll tn=0,tx=0;
    for(int i=1;i<=n;i++){
        a[i]=read();
        while(tn&&a[mn[tn]]>=a[i]) tn--;
        while(tx&&a[mx[tx]]<a[i]) tx--;
        ll k=upper_bound(mn+1,mn+tn+1,mx[tx])-mn;//找最左边的A的坐标
        if(k!=tn+1) ans=max(ans,i-mn[k]+1);
        mn[++tn]=i;
        mx[++tx]=i;
    }
    cout<<ans<<endl;
    return 0;
}

p6812 线段树

黄题直接和绿题不一个档次了,,,Yes的情况是原序列比所有的后缀要屑,那么就是从原序列开始后面的得是个不下降子序列才可以;难点就在于区间合并了:如果右儿子的左端点大于左儿子的右端点且左右儿子都是不下降子序列,那么该区间也是不下降子序列

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007,N = 1000005<<2;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(int a,int b){return a>b;}
ll n,m,a[N],lazy[N];
struct mc{
    ll lw,rw,l,r;
    bool flag;
}e[N];
void hb(ll p){
    e[p].lw=e[p<<1].lw;
    e[p].rw=e[p<<1|1].rw;
    if(e[p<<1].rw<=e[p<<1|1].lw&&e[p<<1].flag&&e[p<<1|1].flag) e[p].flag=1;
    else e[p].flag=0;
}
void upans(mc &x,mc &y,mc &z){
    x.lw=y.lw;
    x.rw=z.rw;
    if(y.rw<=z.lw&&y.flag&&z.flag) x.flag=1;
    else x.flag=0;
}
/*void upans(mc &x,mc &y,mc &z){
	x.lw = y.lw;
	x.rw = z.rw;
	if(y.flag && z.flag && y.rw <= z.lw)x.flag = true;
	else x.flag = false;
}*/
void pushup(ll p,ll w){
    e[p].lw+=w;
    e[p].rw+=w;
    lazy[p]+=w;
}
void pushdown(ll p){
    if(e[p].l == e[p].r)return ;
    pushup(p<<1,lazy[p]);
    pushup(p<<1|1,lazy[p]);
    lazy[p]=0;
}
void build(ll l,ll r,ll p){
    e[p].l=l,e[p].r=r;
    if(l==r){
        e[p].lw=e[p].rw=a[l];
        e[p].flag=1;
        return;
    }
    ll m=l+r>>1;
    build(l,m,p<<1);
    build(m+1,r,p<<1|1);
    hb(p);
}
void update(ll L,ll R,ll w,ll p){
    if(e[p].l>=L&&e[p].r<=R){
        pushup(p,w);
        return;
    }
    pushdown(p);
    ll m=e[p].l+e[p].r>>1;
    if(m>=L) update(L,R,w,p<<1);
    if(m<R) update(L,R,w,p<<1|1);
    hb(p);
}
mc query(ll L,ll R,ll p){
    if(e[p].l>=L&&e[p].r<=R) return e[p];
    pushdown(p);
    ll m=e[p].l+e[p].r>>1;
    mc ans,ans1,ans2;
    if(m>=R) return query(L,R,p<<1);
    else if(m<L) return query(L,R,p<<1|1);
    else{
        ans1=query(L,m,p<<1);
    ans2=query(m+1,R,p<<1|1);
    upans(ans,ans1,ans2);
    }
    return ans;
}
int main(){
    //freopen("in.txt","r",stdin);
    n=read();m=read();
    for(int i=1;i<=n;i++) a[i]=read();
    build(1,n,1);
    while(m--){
        ll op,x,y,w;
        op=read();
        if(op==1){
            x=read();y=read();w=read();
            update(x,y,w,1);
        }
        else{
            x=read();y=read();
            mc ans=query(x,y,1);
            if(ans.flag) printf("Yes\n");
            else printf("No\n");
        }
    }
    return 0;
}

p7715 树状数组,逆序对

勉强能看懂这题,再也不做人少的题了,自己不会,题解还少,就很尴尬

题解P7715 EZEC-10-C Shape - pengyule 的博客 - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007,N = 1000005<<2;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(int a,int b){return a>b;}
ll a[2005][2005],d[2005][2005],f[2005][2005],c[2005],g[2005][2005];
void add(ll x,ll y){
    for(int i=x;i<=2000;i+=lowbit(i)) c[i]+=y;
}
ll ask(ll x){
    ll res=0;
    for(int i=x;i;i-=lowbit(i)) res+=c[i];
    return res;
}
int main(){
    //freopen("in.txt","r",stdin);
    ll n,m;
    n=read();m=read();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++) a[i][j]=read();
    for(int i=1;i<=m;i++){
        ll mx=1;
        for(int j=1;j<=n;j++){
            if(a[j][i]) mx=j+1;
            else d[j][i]=j-mx+1;
        }
        mx=n;
        for(int j=n;j>=1;j--){
            if(a[j][i]) mx=j-1;
            else d[j][i]=min(d[j][i],mx-j+1);
        }
    }
    for(int i=1;i<=n;i++){
        ll mx=m;
        for(int j=m;j>=1;j--){
            if(a[i][j]) mx=j-1;
            else f[i][j]=mx-j+1;
        }
        mx=1;
        for(int j=1;j<=m;j++){
            if(a[i][j]) mx=j+1;
            else g[i][j]=j-mx+1;
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        memset(c,0,sizeof(c));
        for(int j=m,k=m;j>=1;j--){
            if(a[i][j]) continue;
            if(d[i][j]>1){
                while(k>j+f[i][j]-1){
                    if(!a[i][k]) add(d[i][k],-1);
                    k--;
                }
                ans+=(d[i][j]-1)*(ask(n)-ask(d[i][j]-1));
                add(d[i][j],1);//添加逆序对
            }
        }
        memset(c,0,sizeof(c));
        for(int j=1,k=1;j<=m;j++){
            if(a[i][j]) continue;
            if(d[i][j]>1){
                while(k<j-g[i][j]+1){
                    if(!a[i][k]) add(d[i][k],-1);
                    k++;
                }
                ans+=(d[i][j]-1)*(ask(n)-ask(d[i][j]));
                add(d[i][j],1);
            }
        }
    }
    cout<<ans<<endl;
    return 0;
}

p7865 二维差分,二位前缀和

最后求完前缀和看看所求区域是否全部是1,是就yes

P7865题解 - Auspicious Monitor DengZiyue - 洛谷博客 (luogu.com.cn)

#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const ll inf=0x3f3f3f3f3f3f3f3f;
const int mod=1000000007,N = 1000005<<2;
const double eps=1e-11;
ll read() {//快读
    ll x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
void write(int x) {//快写
     if(x<0) putchar('-'),x=-x;
     if(x>9) write(x/10);
     putchar(x%10+'0');
}
ll qpow(ll a,ll b){//快速幂
    ll res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll getinv(ll a,ll mod){return qpow(a,mod-2);}//费马小定理求逆元
bool cmp1(int a,int b){return a>b;}
ll n,m,s,l,a[3005][3005];bool ans;
int main(){
    //freopen("in.txt","r",stdin);
    scanf("%lld%lld",&n,&m);
    memset(a,0,sizeof(a));
    scanf("%d",&s);
    ll x1,y1,x2,y2;
    for(int i=1;i<=s;i++){
        scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
        ++a[x1][y1];++a[x2+1][y2+1];
        --a[x2+1][y1];--a[x1][y2+1];
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        if(a[i][j]) a[i][j]=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
    scanf("%lld",&l);
    for(int i=1;i<=l;i++){
       scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
       if(a[x2][y2]-a[x1-1][y2]-a[x2][y1-1]+a[x1-1][y1-1]>=(x2-x1+1)*(y2-y1+1)) cout<<"Yes"<<endl;
       else cout<<"No"<<endl;
    }
    return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

killer_queen4804

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值