p6242 线段树区间最大值 历史最大值 最小值操作,区间求和混合模板
思路没大懂,但代码理解了。。。
题解 P6242 【【模板】线段树 3】 - - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
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(ll a,ll b){return a>b;}
int n,m,op,l,r,k;
struct tree{
ll sum;
int add_a,add_a1,add_b,add_b1;
int l,r,maxa,se,maxb,cnt;
}tree[2000005];
void push_up(int p){
tree[p].maxa=max(tree[p<<1].maxa,tree[p<<1|1].maxa);
tree[p].maxb=max(tree[p<<1].maxb,tree[p<<1|1].maxb);
tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
if(tree[p<<1].maxa==tree[p<<1|1].maxa){
tree[p].se=max(tree[p<<1].se,tree[p<<1|1].se);
tree[p].cnt=tree[p<<1].cnt+tree[p<<1|1].cnt;
}
if(tree[p<<1].maxa>tree[p<<1|1].maxa){
tree[p].se=max(tree[p<<1].se,tree[p<<1|1].maxa);
tree[p].cnt=tree[p<<1].cnt;
}
if(tree[p<<1].maxa<tree[p<<1|1].maxa){
tree[p].se=max(tree[p<<1].maxa,tree[p<<1|1].se);
tree[p].cnt=tree[p<<1|1].cnt;
}
}
void build(int l,int r,int p){
tree[p].l=l,tree[p].r=r;
if(l==r){
tree[p].sum=tree[p].maxa=tree[p].maxb=read();
tree[p].se=-1e9;
tree[p].cnt=1;
return;
}
int mid=l+r>>1;
build(l,mid,p<<1);
build(mid+1,r,p<<1|1);
push_up(p);
}
void update(int k1,int k2,int k3,int k4,int p){
tree[p].sum+=1ll*k1*tree[p].cnt+1ll*k3*(tree[p].r-tree[p].l+1-tree[p].cnt);
tree[p].maxb=max(tree[p].maxb,tree[p].maxa+k2);
tree[p].add_b=max(tree[p].add_b,tree[p].add_a+k2);
tree[p].add_b1=max(tree[p].add_b1,tree[p].add_a1+k4);
tree[p].maxa+=k1,tree[p].add_a+=k1;
tree[p].add_a1+=k3;
if(tree[p].se!=-1e18) tree[p].se+=k3;
}
void push_down(int p){
int maxn=max(tree[p<<1].maxa,tree[p<<1|1].maxa);
if(tree[p<<1].maxa==maxn)
update(tree[p].add_a,tree[p].add_b,tree[p].add_a1,tree[p].add_b1,p<<1);
else update(tree[p].add_a1,tree[p].add_b1,tree[p].add_a1,tree[p].add_b1,p<<1);
if(tree[p<<1|1].maxa==maxn)
update(tree[p].add_a,tree[p].add_b,tree[p].add_a1,tree[p].add_b1,p<<1|1);
else update(tree[p].add_a1,tree[p].add_b1,tree[p].add_a1,tree[p].add_b1,p<<1|1);
tree[p].add_a=tree[p].add_a1=tree[p].add_b=tree[p].add_b1=0;
}
void update_add(int p){
if(tree[p].l>r||tree[p].r<l) return;
if(l<=tree[p].l&&tree[p].r<=r) return update(k,k,k,k,p);
push_down(p);
update_add(p<<1),update_add(p<<1|1);
push_up(p);
}
void update_min(int p){
if(tree[p].l>r||tree[p].r<l||k>=tree[p].maxa) return;
if(l<=tree[p].l&&tree[p].r<=r&&k>tree[p].se)
return update(k-tree[p].maxa,k-tree[p].maxa,0,0,p);
push_down(p);
update_min(p<<1),update_min(p<<1|1);
push_up(p);
}
ll query_add(int p){
if(tree[p].l>r||tree[p].r<l) return 0;
if(l<=tree[p].l&&tree[p].r<=r) return tree[p].sum;
push_down(p);
return query_add(p<<1)+query_add(p<<1|1);
}
int query_maxa(int p){
if(tree[p].l>r||tree[p].r<l) return -1e9;
if(l<=tree[p].l&&tree[p].r<=r) return tree[p].maxa;
push_down(p);
return max(query_maxa(p<<1),query_maxa(p<<1|1));
}
int query_maxb(int p){
if(tree[p].l>r||tree[p].r<l) return -1e9;
if(l<=tree[p].l&&tree[p].r<=r) return tree[p].maxb;
push_down(p);
return max(query_maxb(p<<1),query_maxb(p<<1|1));
}
int main(){
//freopen("in.txt","r",stdin);
n=read();m=read();
build(1,n,1);
while(m--){
op=read(),l=read(),r=read();
if(op==1) k=read(),update_add(1);
if(op==2) k=read(),update_min(1);
if(op==3) cout<<query_add(1)<<endl;
if(op==4) cout<<query_maxa(1)<<endl;
if(op==5) cout<<query_maxb(1)<<endl;
}
return 0;
}
p1198 rmq区间最值
查询还是那样查询,变得是如何添加数,如果加一次我们就要重新dp一次的话那太浪费时间了,其实我们只要更新那些重点是n的区间就可以了;即i+(1<<j)-1=n==>i=n-(1<<j)+1;
然后去枚举每个j就可以了
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
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(ll a,ll b){return a>b;}
ll n,m,d,t,dp[200005][32],L;
char c;
void change(ll x){
dp[n][0]=x;
for(int j=1;(1<<j)<=n;j++){
ll i=n-(1<<j)+1;//i代表需要更新的区间的起点
dp[i][j]=max(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
}
}
ll rmq(ll l){
int k=log2(n-l+1);
return max(dp[l][k],dp[n-(1<<k)+1][k]);
}
int main(){
// freopen("in.txt","r",stdin);
cin>>m>>d;
while(m--){
cin>>c>>L;
if(c=='A'){
n++;
change((t+L)%d);
}
else{
t=rmq(n-L+1);
cout<<t<<endl;
}
}
return 0;
}
p1774 树状数组求逆序对
树状数组(求逆序对)_卑鄙的我-CSDN博客_树状数组求逆序对
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
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(ll a,ll b){return a>b;}
ll n,t[500005]={0},ans=0;
struct nx{
ll v,id;
}a[500005];
bool cmp(nx a,nx b){
if(a.v==b.v) return a.id>b.id;//按照一开始输入时的顺序排
return a.v>b.v;
}
void update(ll x){
for(int i=x;i<=n;i+=lowbit(i))
t[i]++;
}
ll getsum(int 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;
sort(a+1,a+n+1,cmp);
for(int i=1;i<=n;i++){
update(a[i].id);
ans+=(getsum(a[i].id-1));//因为是按照第几个大来排的顺序,所以这是在求正序对
}
cout<<ans<<endl;
return 0;
}
p1883 三分
三分好像和二分差不了多少,,二分适合单调序列而三分适合凸性的函数序列,比如而二次函数那种,也就是多了个mid
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
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(ll a,ll b){return a>b;}
int t,n;
struct fx{
double a,b,c;
}f[10005];
double check(double x){
double res=-1e9;
for(int i=1;i<=n;i++)
res=max(res,f[i].a*x*x+f[i].b*x+f[i].c);
return res;
}
int main(){
//freopen("in.txt","r",stdin);
cin>>t;
while(t--){
cin>>n;
for(int i=1;i<=n;i++) cin>>f[i].a>>f[i].b>>f[i].c;
double l=0,r=1000,m1,m2;
while(l+eps<r){
m1=l+(r-l)/3.0;
m2=r-(r-l)/3.0;
if(check(m1)>check(m2)) l=m1;
else r=m2;
}
printf("%.4f\n",check(l));
}
return 0;
}
p1886 单调队列模板
题解 P1886 【滑动窗口】 - hankeke 的博客 - 洛谷博客 (luogu.com.cn)
#include<bits/stdc++.h>
#define ll long long
#define lowbit(a) ((a)&(-a))
//typedef __int128 LL;
using namespace std;
const int inf=0x3f3f3f3f;
const int mod=92084931;
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(ll a,ll b){return a>b;}
int n,k;
struct hd1{
int v,id;
bool operator<(const hd1 &a)const{
return v>a.v;
}
}a[1000006];
deque<hd1>q;
void maxx(){
q.clear();
for(int i=1;i<=n;i++){
while(q.size()>0&&q.back().v<=a[i].v) q.pop_back();
q.push_back(a[i]);
while(q.front().id<=i-k) q.pop_front();
if(i>=k) printf("%d ",q.front());
}
cout<<endl;
}
void minn(){
q.clear();
for(int i=1;i<=n;i++){
//只要队列里有元素,并且尾元素比待处理值大,
//即表示尾元素已经不可能出场,所以出队。直到尾元素小于待处理值,满足"单调"。
while(q.size()>0&&q.back().v>=a[i].v) q.pop_back();
q.push_back(a[i]);//待处理值入队。
while(q.front().id<=i-k) q.pop_front();//队首元素已经过时
if(i>=k) printf("%d ",q.front());
}
cout<<endl;
}
int main(){
//freopen("in.txt","r",stdin);
n=read();k=read();
for(int i=1;i<=n;i++){a[i].v=read(),a[i].id=i;}
minn();
maxx();
return 0;
}