2019年秋季学期第七周周任务——YCG

周任务:

算法任务:

树状数组

具体任务:

我康了康pl大佬的博客,才发现我的周任务博客这么不友好,可能也没想谁看吧,以后除了模板题都单独写博客。

HDU1166——敌兵布阵
模板题不说啥了啊

#include<iostream>
#include<stdio.h>
#include<string.h>
using namespace std;
const int maxn = 1e5+5;
int N,sum[maxn],a[maxn]; 
int lowbit(int x){
	return x&-x;
}

void Updata(int pos,int v){
	int ans = 0,index = pos;
	while(index<=N){
		 sum[index] += v;
	     index+=lowbit(index);
	}
}
int Query(int pos){
	int ans = 0;
	while(pos){
		ans+=sum[pos];
		pos-=lowbit(pos);
	}
	return ans;
}

int main(){
	int T,cnt = 0;
	scanf("%d",&T);
	
	while(T--){
	cnt++;  
	printf("Case %d:\n",cnt);
	scanf("%d",&N);
	memset(a,0,sizeof(a));
	memset(sum,0,sizeof(sum));
	for(int i = 1;i <= N;i++)
		 scanf("%d",&a[i]);
	for(int i = 1;i <= N;i++){
		 Updata(i,a[i]);
	}
	 while(1){
	 	string str;
	 	cin >> str;
	 	if(str=="Add"){
	 		int p,v;
	 		scanf("%d%d",&p,&v);
		    Updata(p,v);
		 }
		else  if(str=="Sub"){
		 	int p,v;
		 	scanf("%d%d",&p,&v);
		 	Updata(p,-v);
		 }
		else  if(str=="Query"){
			int l,r;
			scanf("%d%d",&l,&r);
			int ans = Query(r) - Query(l-1);
			printf("%d\n",ans);
		}
		else break;
	 }
	}
	return 0;
} 

POJ2299——Ultra-QuickSort
虽然不难啊,但是博客链接还是得有

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std; 

const int maxn = 5e5+5;
typedef long long ll; 
int N,a[maxn],disc[maxn],sum[maxn];

int lowbit(int x){
	return x&-x;
}

void Updata(int p,int v){
	while(p <= N){
		sum[p]+=v;
		p+=lowbit(p);
	}
}

ll Query(int p){
	int ans = 0;
	while(p){
	   ans+=sum[p];
	   p-=lowbit(p);	
	}
	return ans;
}
int main(){
	while(~scanf("%d",&N)){
		if(N==0)break;
		memset(sum,0,sizeof(sum));
		for(int i = 1;i <= N;i++){
			scanf("%d",&a[i]);
			disc[i] = a[i];
		}
		 sort(disc + 1,disc + 1 + N);
		 ll ans = 0;
	    for(int i = 1;i <= N;i++){
	    	int tmp = lower_bound(disc + 1,disc + 1 + N,a[i]) - disc;
	    	Updata(tmp,1);
	       ans += i -  Query(tmp);
	    
		}	
			printf("%lld\n",ans);
	}
	return 0;
}

2019牛客多校训练营第七场E——Find the median
这题我想说我开始不知道怎么用树状数组写(区间修改的事),用线段树写了(神奇的Bug搞了好久,一气之下重写,一发就过了),后遂发现树状数组可以实现区间修改,但是仍旧觉得不好写,又寻得一篇博客,记录了神奇的解法,完全不需要数学推导,代码贼短,于是依葫芦画瓢,自己写了一遍。
线段树博客
树状数组博客
线段树代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 8e5+5;
int N;
int X1,X2,Y1,Y2,A1,A2,B1,B2,C1,C2,M1,M2;
int L[maxn<<1],R[maxn<<1],disc[maxn<<1],lazy[maxn<<2];
ll Tree[maxn<<2];

void PushDown(int L,int R,int index){
	int Mid = (L + R)>>1;
	lazy[index<<1] += lazy[index];
	lazy[index<<1|1] += lazy[index];
	Tree[index<<1] += lazy[index]*(disc[Mid + 1] - disc[L]);
	Tree[index<<1|1] += lazy[index]*(disc[R + 1] - disc[Mid + 1]);
	lazy[index] = 0;
}
void Updata(int L,int R,int index,int l,int r){
	if(l<=L&&R<=r){
		Tree[index] += (disc[R + 1] - disc[L]);
		lazy[index] += 1;
		return; 
	}
	if(lazy[index])PushDown(L,R,index);
	int Mid = (L + R)>>1;
	if(r<=Mid)Updata(L,Mid,index<<1,l,r);
	else if(l>Mid)Updata(Mid + 1,R,index<<1|1,l,r);
	else {
		Updata(L,Mid,index<<1,l,Mid);
		Updata(Mid + 1,R,index<<1|1,Mid + 1,r);
	}
	Tree[index] = Tree[index<<1] + Tree[index<<1|1];
}
int Query(ll K,int L,int R,int index){
	if(L==R){
	//	printf("%lld %d %d %d\n",K,L,R,index);
		int num = Tree[index]/(disc[R + 1] - disc[L]);
		return disc[L] + (K-1)/num;
	}
//	printf("%lld %d %d %d\n",K,L,R,index);
//	printf("%d\n",Tree[index<<1]);
	int Mid = (L + R)>>1;
	if(lazy[index])PushDown(L,R,index);
	if(K<=Tree[index<<1])return Query(K,L,Mid,index<<1);
	else return Query(K-Tree[index<<1],Mid + 1,R,index<<1|1);
}
int main(){
	 scanf("%d",&N);
	 scanf("%d%d%d%d%d%d",&X1,&X2,&A1,&B1,&C1,&M1);
	 scanf("%d%d%d%d%d%d",&Y1,&Y2,&A2,&B2,&C2,&M2);
	 L[1] = min(X1,Y1) + 1;
	 R[1] = max(X1,Y1) + 1;
	 L[2] = min(X2,Y2) + 1;
	 R[2] = max(X2,Y2) + 1;
	 ll x,y,cnt = 0;
	 for(int i = 3;i <= N;i++){
		x = ((1ll*A1 * X2 % M1 + 1ll * B1 * X1 %M1)%M1 + C1)%M1;
		y = ((1ll*A2 * Y2 % M2 + 1ll * B2 * Y1 %M2)%M2 + C2)%M2;
		X1 = X2;X2 = x;
		Y1 = Y2;Y2 = y;
		L[i] = min(x,y) + 1;
		R[i] = max(x,y) + 1;
	}
		for(int i = 1;i <= N;i++){
		disc[++cnt] = L[i];
		disc[++cnt] = R[i] + 1;
	//	printf("%d %d\n",L[i],R[i]);
	}
	memset(Tree,0,sizeof(Tree));
	memset(lazy,0,sizeof(lazy));
	sort(disc + 1,disc + 1 + cnt);
	int count = unique(disc + 1,disc + 1 + cnt) - disc - 1;
	ll All = 0;
	for(int i = 1;i <= N;i++){
		int l,r;
		All += R[i] - L[i] + 1;
	
		l = lower_bound(disc + 1,disc + count + 1,L[i]) - disc;
		r = lower_bound(disc + 1,disc + count + 1,R[i] + 1) - disc; 
	//	printf("%d %d\n",l,r);
		Updata(1,count,1,l,r-1);
		printf("%d\n",Query((All+1)/2,1,count,1));
	}
	
	return 0;
}

树状数组代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 8e5+5;
const int INF = 1e9;
int N;
int X1,X2,Y1,Y2,A1,A2,B1,B2,C1,C2,M1,M2;
int L[maxn],R[maxn],disc[maxn<<1];
ll b1[maxn],b2[maxn],cnt = 0;
int lowbit(int x){
    return x&-x;
}

void Updata(ll a[],int pos,int value){
    while(pos <= cnt){
        a[pos] += value;
        pos += lowbit(pos);
    }
}
ll Query(ll a[],int x){
    ll ans = 0;
    while(x){
        ans += a[x];
        x -= lowbit(x);
    }
    return ans;
}
int main(){
	 scanf("%d",&N);
	 scanf("%d%d%d%d%d%d",&X1,&X2,&A1,&B1,&C1,&M1);
	 scanf("%d%d%d%d%d%d",&Y1,&Y2,&A2,&B2,&C2,&M2);
	 L[1] = min(X1,Y1) + 1;
	 R[1] = max(X1,Y1) + 1;
	 L[2] = min(X2,Y2) + 1;
	 R[2] = max(X2,Y2) + 1;
	 ll x,y;
	 for(int i = 3;i <= N;i++){
		x = ((1ll*A1 * X2 % M1 + 1ll * B1 * X1 %M1)%M1 + C1)%M1;
		y = ((1ll*A2 * Y2 % M2 + 1ll * B2 * Y1 %M2)%M2 + C2)%M2;
		X1 = X2;X2 = x;
		Y1 = Y2;Y2 = y;
		L[i] = min(x,y) + 1;
		R[i] = max(x,y) + 1;
	}
		for(int i = 1;i <= N;i++){
		disc[++cnt] = L[i];
		disc[++cnt] = R[i] + 1;
	//	printf("%d %d\n",L[i],R[i]);
	}
	memset(b1,0,sizeof(b1));
	memset(b2,0,sizeof(b2));
	sort(disc + 1,disc + 1 + cnt);
	 cnt = unique(disc + 1,disc + 1 + cnt) - disc - 1;
	ll All = 0;
	for(int i = 1;i <= N;i++){
		int l,r;
		All += R[i] - L[i] + 1;
		l = lower_bound(disc + 1,disc + cnt + 1,L[i]) - disc;
		r = lower_bound(disc + 1,disc + cnt + 1,R[i] + 1) - disc; 
        Updata(b1,l,-L[i]);
        Updata(b1,r,R[i]+1);
        Updata(b2,l,1);
        Updata(b2,r,-1);
        int left = 1,right = INF;
        ll pd = (All + 1)/2;
        while(left < right){
            int mid = (left + right)>>1;
            int pos = upper_bound(disc + 1,disc + cnt + 1,mid) - disc - 1;
            ll tmp = Query(b1,pos) + Query(b2,pos)*(mid + 1);
            if(tmp < pd) left = mid + 1;
            else right = mid;
        }
        printf("%d\n",left);
	}
	
	return 0;
}

最后一题先给别人的代码,日后自己在写吧:

#include <bits/stdc++.h>
using namespace std;
typedef long long lint;
const int maxn = 100005;
const int maxm = 100005;
int E[maxn],L[maxn],C[maxn],d[maxn],mx;
vector<int> st[maxn],en[maxn];
set<int> se;
void init( int n ){
    se.clear();
    for( int i = 0; i<= n;i++ ) st[i].clear(),en[i].clear();
}
struct fanwick{
    lint limit,b[200005];
    void init( int mx ){
        limit = mx+1;
        for( int i = 0;i <= limit;i++ ) b[i] = 0;
    }
    int lowbit(int x){
        return x&-x;
    }
    void add( int x,lint v ){
        while(x<=limit){
            b[x] += v;
            x += lowbit(x);
        }
    }
    lint ask( lint x ){
        lint res = 0;
        if( x > limit ) x = limit;
        while(x){
            res += b[x];
            x -= lowbit(x);
        }
        return res;
    }
    lint query( int l,int r ){
        if( l > r ) return 0;
        return ask(r)-ask(l-1);
    }
}g1,g2;
lint ans = 0;
void solve( int x ){
    if( se.size() ){
        auto p = se.begin();
        if( L[x] && *p >= (C[x]-E[x]+L[x]-1)/L[x]  ) ans += C[x];
        else ans += E[x] + L[x]* *p;
 
        ans += g2.ask( d[x]-1 ) * L[x];
        ans += g1.query( d[x],g1.limit ) * C[x] ;
    }
}
int main(){
    int n,T,l,r;
    scanf("%d",&T);
    for( int tt = 1;tt <= T;tt++ ){
        printf("Case #%d: ",tt);
        ans = mx = 0;
        scanf("%d",&n);init(n);
        for( int i = 1;i <= n;i++ ) {
            scanf("%d%d%d",&E[i],&L[i],&C[i]);
            d[i] =  L[i] ?(C[i] + L[i]-1)/L[i] : 1e6+1 ;
        }
        int m,t;
        scanf("%d",&m);
        for(int i = 1;i <= m;i++1 ) {
            scanf("%d%d%d",&t,&l,&r);
            st[l].push_back( t );
            en[r+1].push_back(t);
            mx = max( mx,t );
        }
        g1.init(mx);g2.init(mx);
        for( int i = 1;i <= n;i++ ){
            for( auto x : st[i] ){
                se.insert(x);
                auto p = se.find(x);
                auto pre = p,suf = p;
                if( p != se.begin() ) --pre;
                if( p != se.end() ) ++suf;
                    if( p != se.begin() ){
                        int dt = *p-*pre;
                        g1.add( dt,1 );g2.add( dt,dt );
                    }
                    if( suf != se.end() ){
                        int dt = *suf-*p;
                        g1.add( dt,1 );g2.add( dt,dt );
                        if(p!=se.begin()){
                            int dt = *suf-*pre;
                            g1.add( dt,-1 );g2.add( dt,-dt );
                        }
                    }
            }
            for( auto x : en[i] ){
                auto p = se.find( x );
                auto suf = p,pre = p;
                if( p != se.begin() )--pre;
                if( p != se.end() ) ++suf;
                if( p != se.begin() ){
                    int dt = *p - *pre;
                    g1.add( dt,-1 );g2.add( dt,-dt );
                }
                if( suf != se.end() ){
                    int dt  = *suf - *p;
                    g1.add( dt,-1 );g2.add( dt,-dt );
                    if( p != se.begin() ){
                        dt = *suf - *pre;
                        g1.add( dt,1 );g2.add( dt,dt );
                    }
                }
                se.erase(p);
            }
            solve(i);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值