zoukankan      html  css  js  c++  java
  • [UPC10525]:Dove打扑克(暴力+模拟)

    题目描述

      $Dove$和$Cicada$是好朋友,他们经常在一起打扑克来消遣时光,但是他们打的扑克有不同的玩法。
      最开始时,牌桌上会有$n$个牌堆,每个牌堆有且仅有一张牌,第$i$个牌堆里里里那个扑克牌的编号为$i$,任意两张牌仅有标号不不同。游戏会进行$m$轮,每轮$Dove$可以执行行下列操作之一:
      $ullet 1 x y$,将编号为$x,y$的牌所在的牌堆合并,如果此时$x,y$已在同一牌堆中,那么不进行任何操作。
      $ullet 2 c$,询问有多少对牌堆的牌数之差不少于$c$。形式化的,对于当前的$r$个牌堆中,有多少对$i,j(i<j)$,满足$|size_i-size_j|geqslant c$,其中$size_i$表示第$i$个牌堆的牌数。
      每次$Cicada$都不能很快的回答出$Dove$的询问,为了不让$Cicada$难堪,$Dove$想要写一个小程序来帮助$Cicada$,但是$Dove$还要把妹学高考,所以这个任务就交给你啦!


    输入格式

      第一行两个空格隔开的整数$n,m$。
      接下来$m$行,每行为$1 x y$或者$2 c$,具体含义如上文所示。


    输出格式

      对于每个询问,输出一行一个整数表示答案。


    数据范围与提示

    $n,cleqslant 10^5,mleqslant 3 imes 10^5$


    题解

    显然答案就是$sum limits_{i=1}^ns[i] imes s[<(i-c)]$,其中$s[i]$表示有$i$个石子的堆的个数。

    用树状数组即可快速求出$s[<(i-c)]$,由于同时最多只会有$sqrt{n}$个不同的$s[i]$,于是去个重就好了。

    时间复杂度:$Theta(nsqrt{n}log n)$。

    期望得分:$100$分。

    实际得分:$100$分。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    int n,m,t;
    int fa[100001],bl[100001],size[100001],num[100001];
    long long ans[2][100001];
    vector<int> vec;
    int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    void change(int x,int w){ans[0][x]+=w;ans[1][bl[x]]+=w;}
    void del(int x)
    {
    	if(x<=t)num[x]--;
    	else vec.erase(lower_bound(vec.begin(),vec.end(),x));
    	for(int i=1;i<=t;i++)change(abs(x-i),-num[i]);
    	for(auto i:vec)change(abs(x-i),-1);
    }
    void add(int x,int y)
    {
    	for(int i=1;i<=t;i++)change(abs(size[x]-i),num[i]);
    	for(auto i:vec)change(abs(size[x]-i),1);
    	if(size[x]<=t)num[size[x]]++;
    	else vec.insert(lower_bound(vec.begin(),vec.end(),size[x]),size[x]);
    }
    long long ask(int x)
    {
    	long long res=0;
    	for(int i=x;i<=bl[x]*t;i++)res+=ans[0][i];
    	for(int i=bl[x]+1;i<=bl[n];i++)res+=ans[1][i];
    	return res;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	t=sqrt(n);
    	for(int i=1;i<=n;i++)
    	{
    		fa[i]=i;
    		size[i]=1;
    		bl[i]=(i-1)/t+1;
    	}
    	num[1]=n;ans[0][0]=ans[1][0]=1LL*n*(n-1)/2;
    	while(m--)
    	{
    		int opt;scanf("%d",&opt);
    		switch(opt)
    		{
    			case 1:
    				int x,y;
    				scanf("%d%d",&x,&y);
    				x=find(x);y=find(y);
    				if(x==y)continue;
    				del(size[x]);
    				del(size[y]);
    				size[x]+=size[y];
    				fa[y]=x;
    				add(x,y);
    			break;
    			case 2:
    				int c;scanf("%d",&c);
    				printf("%lld
    ",ask(max(c,0)));
    			break;
    		}
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    vSan中见证组件witness详解
    zabbix监控企业esxi虚拟机
    新特性之MAPI over HTTP 配置 MAPI over HTTP
    Exchange Server 产品路线图 及 补丁下载
    人生的第一桶金
    这不是我想要的生活,努力才是王道!
    孤独的灵魂该去何处安家
    如何查看myeclipse是否激活
    Visual Studio 2013如何破解(密钥激活)
    unity破解步骤
  • 原文地址:https://www.cnblogs.com/wzc521/p/11753576.html
Copyright © 2011-2022 走看看