p6225 位运算+树状数组
通过这题发现异或大概是满足交换和结合律的,然后就可以发现规律了
-
当 l,u奇偶性不同时,[l,u] 中所有元素都会对答案贡献偶数次 ,那么答案就是 0。
-
当 l,u奇偶性相同时,[l,u] 中所有 l,u奇偶性相同的位置的值会对答案贡献奇数次,其他位置的值则会贡献偶数次,那么答案就是 a[l]^a[l+2]^a[l+4]^...^a[u]。题解 P6225 【[eJOI2019]异或橙子】 - _Wallace_ - 洛谷博客 (luogu.org)
#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;
}