bzoj3211花神游历各国

Description

Input

Output

每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input

4

1 100 5 5

5

1 1 2

2 1 2

1 1 2

2 2 3

1 1 4

Sample Output

101

11

11

HINT

对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9

Source

SPOJ2713 gss4 数据已加强

看了好几道并查集的题都不会都说是和这道题一模一样
那么我们来看看这道题把。
首先可以用线段树暴力做复杂度大概多个log
线段树做就是暴力做法吧
我们来学习一下树状数组加并查集的更暴力的做法吧
思路是暴力修改l到r然后用并查集跳过那些已经不能继续开方的数
大概基本很多人的修改都是下面的这一句话

for(int j=l;j<=r;add(j,(t=(int)sqrt(a[j]))-a[j]),a[j]=t,
        f[j]=(a[j]<=1)?j+1:j,j=(find(j)==j?j+1:f[j]));

!这种东西我能看懂么
不存在的
不过好像第一行就是暴力修改的意思没啥可想的
如果j已经被削到1以下(开方没变化),那么原来连向j的那些应该指向j+1了,否则还指向j
第二句表示如果j还指向自己那么就一位一位走,否则直接从父亲转移。
对于正确性我觉得随便手玩一下就懂了
那么我们学会了新知识!!!
虽然只是能看懂自己根本写不出来

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read()
{
    char ch='*';
    int f=1;
    while(!isdigit(ch=getchar())) if(ch=='-') f=-1;
    int num=ch-'0';
    while(isdigit(ch=getchar())) num=num*10+ch-'0';
    return num*f;
}
typedef long long ll;
const int maxn = 100005;
ll c[maxn];
int a[maxn],f[maxn],n,m,op,l,r,t;
int find(int x){return x==f[x]? x:f[x]=find(f[x]);}
inline void add(int x ,int num) {while(x<=n) c[x]+=num,x+=x&-x;}
inline ll sum(int x){ll s = 0;while(x) s+=c[x],x-=x&-x;return s;}
int main()
{
    n=read();
    for(register int i=1;i<=n;i++) f[i]=i,a[i]=read(),add(i,a[i]);
    m=read();f[n+1]=n+1;
    for(register int i=1;i<=m;i++)
    {
        op=read();l=read();r=read();
        if(op==1){
            printf("%lld\n",(sum(r)-sum(l-1)));
        }
         else for(int j=l;j<=r;add(j,(t=(int)sqrt(a[j]))-a[j]),a[j]=t,
        f[j]=(a[j]<=1)?j+1:j,j=(find(j)==j?j+1:f[j]));
    }
    return 0;
}


你可能感兴趣的:(并查集实现,暴力,数据结构,想法)