首页 > 代码库 > hdu-1698-Just a Hook.

hdu-1698-Just a Hook.

In the game of DotA,Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.



Now Pudge wants to do some operations on the hook.

Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:

For each cupreous stick, the value is 1.
For each silver stick, the value is 2.
For each golden stick, the value is 3.

Pudge wants to know the total value of the hook after performing the operations.
You may consider the original hook is made up of cupreous sticks.
 

Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.
 

Output
For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.

题意如下:

dota里面有一个hero名为Pudge,他有一个用链子连着的铁钩,一开始他的链子全是一块一块的铜块(价值为1)连接而制的,现在他可以选择任意长度(从i到j)然后对其进行改造,可以改成银块(价值为2),也可以改成金块(价值为3),然后在Q次改造后,要求你求出现在他的链子的总价值是多少!!!

这个题简化的话--->就是给出一个长度为n的数组,初始值全为1,然后在Q次改变指定长度的子数组的值后,再求出这个长度为n的数组的总值大小!

思路:使用线段树来做!百度线段树的地址:--->>>线段树

说起来有点拗口,在本子上画一个线段树便一目了然了!)

一开始进行建树操作!然后再进行更新操作,即将一个K值赋值给数组里一个指定的区间,更新的时候需要注意下:如果一个节点所在的区间没有被num[i,j]这个区间完全包含,则需向下更新,同时还要将之前的更新还原给【以前需要更新但是没有进行更新的节点】(此时可以用flag[]数组来判断这个节点是否是之前需要更新但是却没有更新的节点);如果被完全包含了,则不用再继续向下更新了,直接将当前被包含区间进行一系列操作即可(赋值,标记)!

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=201314;
int sum[maxn<<2],flag[maxn<<2];
void s_s(int num)
{
    sum[num]=sum[num<<1]+sum[num<<1|1];
}
void build(int l,int r,int chu,int num)
{
    sum[num]=chu;//初始化更新,因为全部都是铜块!!!
    flag[num]=0;//表明此时没有更新动作!
    if(l==r)
        return ;
    int m=(r+l)>>1;
    build(l,m,chu,num<<1);
    build(m+1,r,chu,num<<1|1);
}
void gb(int num,int len)
{
    if(flag[num])
    {
        flag[num<<1|1]=flag[num<<1]=flag[num];//向下传给子节点保存以前更新所改变的值!
        sum[num<<1]=flag[num]*(len-(len>>1));
        sum[num<<1|1]=flag[num]*(len>>1);
        flag[num]=0;//然后将其状态改变为未更新!
    }
}
void update(int i,int j,int l,int r,int k,int num)
{
    if(i<=l&&j>=r)
    {
        sum[num]=k*(r-l+1);//表明当前区间已完全被包含于所需改变区间,此时直接赋值!
        flag[num]=k;//更改状态!
        return ;
    }
    gb(num,r-l+1);//向下给子节点传导父节点的状态!
    int m=(l+r)/2;
    if(i<=m)
        update(i,j,l,m,k,num<<1);//如果此时所求区间有一部分在左子节点,则继续更新
    if(j>m)
        update(i,j,m+1,r,k,num<<1|1);//如果此时所求区间有一部分在右子节点,则继续更新
    sum[num]=sum[num<<1]+sum[num<<1|1];//最后再次求所求区间的求和!
}
int main()
{
    int T;
    cin>>T;
    for(int ji=1; ji<=T; ji++)
    {
        int n,Q;
        cin>>n;
        build(1,n,1,1);
        cin>>Q;
        while(Q--)
        {
            int x,y,z;
            cin>>x>>y>>z;
            update(x,y,1,n,z,1);
            //for(int i=1; i<20; i++)
                //if(sum[i])
              //      cout<<sum[i]<<",";
            //cout<<"--->"<<sum[1]<<endl;
        }
        printf("Case %d: The total value of the hook is %d.\n",ji,sum[1]);
    }
    return 0;
}