Codeforces Round #254 (Div. 2)(并查集,线段树)

B. DZY Loves Chemistry
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

DZY loves chemistry, and he enjoys mixing chemicals.

DZY has n chemicals, and m pairs of them will react. He wants to pour these chemicals into a test tube, and he needs to pour them in one by one, in any order.

Let's consider the danger of a test tube. Danger of an empty test tube is 1. And every time when DZY pours a chemical, if there are already one or more chemicals in the test tube that can react with it, the danger of the test tube will be multiplied by2. Otherwise the danger remains as it is.

Find the maximum possible danger after pouring all the chemicals one by one in optimal order.

Input

The first line contains two space-separated integers n andm .

Each of the next m lines contains two space-separated integersxi andyi(1 ≤ xi < yi ≤ n). These integers mean that the chemicalxi will react with the chemicalyi. Each pair of chemicals will appear at most once in the input.

Consider all the chemicals numbered from 1 to n in some order.

Output

Print a single integer — the maximum possible danger.

Sample test(s)
Input
1 0
Output
1
Input
2 1
1 2
Output
2
Input
3 2
1 2
2 3
Output
4
Note

In the first sample, there's only one way to pour, and the danger won't increase.

In the second sample, no matter we pour the 1st chemical first, or pour the2nd chemical first, the answer is always 2.

In the third sample, there are four ways to achieve the maximum possible danger: 2-1-3, 2-3-1, 1-2-3 and 3-2-1 (that is the numbers of the chemicals in order of pouring).


思路:同一集合中的元素最多肯定是反应n-1次,所以用并查集统计这个集合中的元素有多少个

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
const int MAXN=60;
typedef long long LL;
using namespace std;
int N,M,p[MAXN],cnt[MAXN];
int find(int x)
{
    return x==p[x]?x:p[x]=find(p[x]);
}
int main()
{
    scanf("%d%d",&N,&M);
    for(int i=1; i<=N; i++)
    {
        cnt[i]=1;
        p[i]=i;
    }
    int u,v;
    for(int i=0; i

E. DZY Loves Colors
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

DZY loves colors, and he enjoys painting.

On a colorful day, DZY gets a colorful ribbon, which consists of n units (they are numbered from 1 ton from left to right). The color of the i-th unit of the ribbon is i at first. It is colorful enough, but we still consider that the colorfulness of each unit is0 at first.

DZY loves painting, we know. He takes up a paintbrush with color x and uses it to draw a line on the ribbon. In such a case some contiguous units are painted. Imagine that the color of uniti currently is y. When it is painted by this paintbrush, the color of the unit becomesx, and the colorfulness of the unit increases by|x - y|.

DZY wants to perform m operations, each operation can be one of the following:

  1. Paint all the units with numbers between l andr (both inclusive) with color x.
  2. Ask the sum of colorfulness of the units between l andr (both inclusive).

Can you help DZY?

Input

The first line contains two space-separated integers n, m (1 ≤ n, m ≤ 105).

Each of the next m lines begins with a integertype (1 ≤ type ≤ 2), which represents the type of this operation.

If type = 1, there will be 3 more integers l, r, x (1 ≤ l ≤ r ≤ n; 1 ≤ x ≤ 108) in this line, describing an operation1.

If type = 2, there will be 2 more integers l, r (1 ≤ l ≤ r ≤ n) in this line, describing an operation2.

Output

For each operation 2, print a line containing the answer — sum of colorfulness.

Sample test(s)
Input
3 3
1 1 2 4
1 2 3 5
2 1 3
Output
8
Input
3 4
1 1 3 4
2 1 1
2 2 2
2 3 3
Output
3
2
1
Input
10 6
1 1 5 3
1 2 7 9
1 10 10 11
1 3 8 12
1 1 10 3
2 1 10
Output
129
Note

In the first sample, the color of each unit is initially [1, 2, 3], and the colorfulness is [0, 0, 0].

After the first operation, colors become [4, 4, 3], colorfulness become[3, 2, 0].

After the second operation, colors become [4, 5, 5], colorfulness become[3, 3, 2].

So the answer to the only operation of type 2 is8.


线段树,比赛的时候敲了一个多小时,最后发现自己看错题了。。。

赛后看别人的代码,果然是大神。

本来想的是维护区间上的和没然后set标记后,可以直接相减得到该区间上的变化量,后来发现是错的,这样相当于没有取绝对值。从别人的代码中得到启发,果然很神奇。需要有一个sum维护区间上变化量的总值,val维护前面的所有操作改变量的总和,setv表示当前图的颜色。当前这一段如果没有被吐过,则一定会更新到底。其他的详见代码。

#include
#include
#include
#include
using namespace std;
const int maxn=100010;
typedef long long LL;
int n,m;
struct IntervalTree
{
    LL sum[maxn<<3],setv[maxn<<3],val[maxn<<3];
    void pushup(int o)
    {
        sum[o]=sum[o<<1]+sum[o<<1|1];
        if(setv[o<<1]==setv[o<<1|1])setv[o]=setv[o<<1];//如果左右孩子的setv一样表示他们的颜色是一样的那么父亲节点的setv值就可以更新
        else setv[o]=0;
    }
    void build(int o,int l,int r)
    {
        sum[o]=val[o]=setv[o]=0;
        if(l==r)
        {
            setv[o]=l;
            return ;
        }
        int mid=(l+r)/2;
        build(o<<1,l,mid);
        build(o<<1|1,mid+1,r);
        pushup(o);
    }
    void pushdown(int o,int l,int r)
    {
        if(val[o])
        {
            int mid=(l+r)>>1;
            sum[o<<1]+=val[o]*(mid-l+1);//这里只能是用父节点的val来更新sum,不能用val[o<<1]*(r-l+1),因为以前的sum个能是左右孩子来更新的
            sum[o<<1|1]+=val[o]*(r-mid);
            val[o<<1]+=val[o];
            val[o<<1|1]+=val[o];
            setv[o<<1]=setv[o<<1|1]=setv[o];
            val[o]=setv[o]=0;
        }
    }
    void update(int o,int l,int r,int q1,int q2,LL x)
    {
        if(q1<=l&&r<=q2)
        {
            if(setv[o])//setv不等于0说明这个区间以前被涂过色,可以直接用(r-l+1)*abs(setv[o]-x)算出这次的变化,如果不是0,则因为绝对值的原因不能直接这样算,需要从她的孩子节点来维护她
            {
                sum[o]+=(r-l+1)*abs(setv[o]-x);
                val[o]+=abs(setv[o]-x);
                setv[o]=x;
                return;
            }
        }
        int mid=(l+r)>>1;
        pushdown(o,l,r);//往下推的是val这个差值的总和和setv
        if(q1<=mid)update(o<<1,l,mid,q1,q2,x);
        if(q2>mid)update(o<<1|1,mid+1,r,q1,q2,x);
        pushup(o);//根据孩子的值维护父亲
    }
    LL query(int o,int l,int r,int q1,int q2)
    {
        int mid=((l+r)/2);
        if(q1<=l&&r<=q2)
            return sum[o];
        pushdown(o,l,r);
        LL x=0,y=0;
        if(q1<=mid)x=query(o<<1,l,mid,q1,q2);
        if(q2>mid)y=query(o<<1|1,mid+1,r,q1,q2);
        pushup(o);
        return x+y;
    }
}tree;
int main()
{
    freopen("in.txt","r",stdin);
    int op,a,b,v;
    scanf("%d%d",&n,&m);
    tree.build(1,1,n);
    while(m--)
    {
        scanf("%d%d%d",&op,&a,&b);
        if(op==1)
        {
            scanf("%d",&v);
            tree.update(1,1,n,a,b,v);
        }
        else cout<




你可能感兴趣的:(数据结构,树状数组/线段树)