zoukankan      html  css  js  c++  java
  • 解题报告:luogu P4879

    题目链接:P4879 ycz的妹子
    操作很多,但都是吓人的。
    一眼线段树,我不会告诉你我是搜线段树标签找到这题的
    考虑用每个节点来维护每个城市中妹子的情况,显然只需维护:妹子的颜值与此城市是否有热恋中的妹子。
    开始想维护两个线段树,经过冷静后发现在一棵线段树上搞即可。
    看数据范围,知道要注意(long;long)
    来看基本操作(应该都是小儿科的了):
    (1).更新及建树:

    void update(int k){a[k].sum=a[k<<1].sum+a[k<<1|1].sum,a[k].cnt=a[k<<1].cnt+a[k<<1|1].cnt;}
    void build(int k,int l,int r,int x)
    {
    	a[k].l=l,a[k].r=r;
    	if(l==r)
    	{
    		if(l<=x) a[k].cnt++;
    		a[k].sum=(ll)t[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(k<<1,l,mid,x),build(k<<1|1,mid+1,r,x);
    	update(k);
    }
    

    (2).把一个城市妹子颜值降低:

    void turn(int k,int x,int y)
    {
    	if(a[k].l==a[k].r){a[k].sum-=(ll)y;return;}
    	int mid=(a[k].l+a[k].r)>>1;
    	if(x<=mid) turn(k<<1,x,y);
    	else turn(k<<1|1,x,y);
    	update(k);
    }
    

    (3).在一个城市上加一个妹子,注意把有妹子的标记打上:

    void turn_to(int k,int x,int y)
    {
    	if(a[k].l==a[k].r){a[k].sum=(ll)y,a[k].cnt=1;return;}
    	int mid=(a[k].l+a[k].r)>>1;
    	if(x<=mid) turn_to(k<<1,x,y);
    	else turn_to(k<<1|1,x,y);
    	update(k);
    }
    

    (4).寻找第(x)个有妹子的城市:
    这时候就要用到有无妹子的计数器了,我们在线段树上每次判断是在左儿子还是在右儿子即可。和权值线段树确定第(k)大(小)数的思想是一样的。

    int find(int k,int x)
    {
    	if(a[k].l==a[k].r){return a[k].l;}
    	int mid=a[k<<1].cnt;
    	if(x<=mid) return find(k<<1,x);
    	else return find(k<<1|1,x-mid);
    }
    

    (5).把在某个城市的妹子踢掉。
    这里的函数名十分生动:(kick)......
    我们把颜值设成(0),并把标记打成“无妹子”即可。

    void kick(int k,int x)
    {
    	if(a[k].l==a[k].r){a[k].cnt=a[k].sum=(ll)0;return;}
    	int mid=(a[k].l+a[k].r)>>1;
    	if(x<=mid) kick(k<<1,x);
    	else kick(k<<1|1,x);
    	update(k);
    }
    

    (6).颜值和:
    由于是所有数的和,只需输出树根的总颜值即可。
    需要注意的是:对于所有修改操作,记得不断更新((update))。
    在这里提供一个拓展题:把查询总颜值改为每次求可以得到妹子的最大颜值,这样的难度就有了提高,大家可以想一下做法。
    下面给出完整代码:

    (Code)

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    #define MAXN 500005
    #define ll long long
    int n,m,x,y,t[MAXN];
    char c;
    struct node
    {
    	int l,r,cnt;
    	ll sum;	
    	node(){sum=cnt=(ll)0;}
    }a[MAXN<<2];
    void update(int k){a[k].sum=a[k<<1].sum+a[k<<1|1].sum,a[k].cnt=a[k<<1].cnt+a[k<<1|1].cnt;}
    void build(int k,int l,int r,int x)
    {
    	a[k].l=l,a[k].r=r;
    	if(l==r)
    	{
    		if(l<=x) a[k].cnt++;
    		a[k].sum=(ll)t[l];
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(k<<1,l,mid,x),build(k<<1|1,mid+1,r,x);
    	update(k);
    }
    void turn(int k,int x,int y)
    {
    	if(a[k].l==a[k].r){a[k].sum-=(ll)y;return;}
    	int mid=(a[k].l+a[k].r)>>1;
    	if(x<=mid) turn(k<<1,x,y);
    	else turn(k<<1|1,x,y);
    	update(k);
    }
    void turn_to(int k,int x,int y)
    {
    	if(a[k].l==a[k].r){a[k].sum=(ll)y,a[k].cnt=1;return;}
    	int mid=(a[k].l+a[k].r)>>1;
    	if(x<=mid) turn_to(k<<1,x,y);
    	else turn_to(k<<1|1,x,y);
    	update(k);
    }
    int find(int k,int x)
    {
    	if(a[k].l==a[k].r){return a[k].l;}
    	int mid=a[k<<1].cnt;
    	if(x<=mid) return find(k<<1,x);
    	else return find(k<<1|1,x-mid);
    }
    void kick(int k,int x)
    {
    	if(a[k].l==a[k].r){a[k].cnt=a[k].sum=(ll)0;return;}
    	int mid=(a[k].l+a[k].r)>>1;
    	if(x<=mid) kick(k<<1,x);
    	else kick(k<<1|1,x);
    	update(k);
    }
    int main()
    {
    	#define read(x) scanf("%d",&x)
    	read(n),read(m);
    	for(int i=1;i<=m;i++) read(t[i]);
    	build(1,1,500000,n);
    	for(int i=1;i<=m;i++)
    	{
    		cin>>c;
    		if(c=='C') read(x),read(y),turn(1,x,y);
    		else if(c=='I') read(x),read(y),turn_to(1,x,y);
    		else if(c=='D') read(x),y=find(1,x),kick(1,y);
    		else printf("%lld
    ",a[1].sum);
    	}
    	return 0;
    }
    
  • 相关阅读:
    D. Constructing the Array
    B. Navigation System
    B. Dreamoon Likes Sequences
    A. Linova and Kingdom
    G. Special Permutation
    B. Xenia and Colorful Gems
    Firetrucks Are Red
    java getInstance()的使用
    java 静态代理和动态代理
    java 类加载机制和反射机制
  • 原文地址:https://www.cnblogs.com/tlx-blog/p/12639521.html
Copyright © 2011-2022 走看看