码迷,mamicode.com
首页 > 其他好文 > 详细

hdu 4339 线段树+二分

时间:2015-01-21 18:21:04      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:线段树


题意是给你两个字符串    进行两种操作   1: 修改其中一个字符串里的某个字符2:   询问从i起两个字符串最多由多少个是相同的;


先说一下做之前的想法   ,我是看别人介绍树状数组是看到这道题的    本也想用树状数组做  ,没想上去    然后就改为线段树了   ,有很明显的点更新,区间查询,所以选择线段树;


思路:  每个节点num【】 存3个值       p1  p2  flash   flash表示当前节点两个字符串是不是一样的   若是则为1否则为0    p1 p2为当前两个字符串的字符(其实只有在最底端的节点  p1  p2才有意义)  题目给的是字符区间  而真正修改的是点    所以得先处理字符串加到线段树里也就是deal函数  (偷懒写在一个函数里果断超时了!!!)    然后对点来更新 

对于查询 我是用的二分      开始j=最大长度     然后二分到底   虽然时间可能长点   但代码比较简单


#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;

#define LL(x) (x<<1)
#define RR(x) ((x<<1)|1)

char str1[1000010],str2[1000010];
struct node
{
    char p1,p2;
    int flash;
}num[4*1000000];
int max(int a,int b)
{
    return a>b?a:b;
}
int deal(int L,int R,int left,int right,int mark,int k,char str[])
{    
    if(L==left&&right==R&&L==R)
    {
        if(k==1) num[mark].p1=str[L-1];
        else num[mark].p2=str[L-1];
        if(num[mark].p1==num[mark].p2) num[mark].flash=1;
        else num[mark].flash=0;
        return 0;
    }
    int mid=(L+R)/2;
    if(right<=mid)
    {
        deal(L,mid,left,right,LL(mark),k,str);
    }    
    else if(left>mid)
    {
        deal(mid+1,R,left,right,RR(mark),k,str);
    }
    else
    {
        deal(L,mid,left,mid,LL(mark),k,str);
        deal(mid+1,R,mid+1,right,RR(mark),k,str);
    }
    if(num[LL(mark)].flash==0||num[RR(mark)].flash==0) num[mark].flash=0;
    else num[mark].flash=1;
    return 0;
}
int update(int L,int R,int dis,int mark,int k,char p)
{
    if(L==R&&L==dis)
    {
        if(k==1) num[mark].p1=p;
        else num[mark].p2=p;
        if(num[mark].p1==num[mark].p2) num[mark].flash=1;
        else num[mark].flash=0;
        return 0;
    }
    if(num[mark].flash==1)
    {
        num[LL(mark)].flash=num[RR(mark)].flash=num[mark].flash;
    }
    int mid=(L+R)/2;
    if(dis<=mid)
    {
        update(L,mid,dis,LL(mark),k,p);
    }    
    else update(mid+1,R,dis,RR(mark),k,p);
    if(num[LL(mark)].flash==0||num[RR(mark)].flash==0)
    {
        num[mark].flash=0;
    }
    else  num[mark].flash=1; 
    return 0;
}
int find(int L,int R ,int left,int right,int mark)
{
    if(num[mark].flash==1) return 1;
    if(left==L&&right==R) return -1;
    int mid=(L+R)/2;
    if(right<=mid)
    {
        return find(L,mid,left,right,LL(mark));
    }
    else if(left>mid)
    {
        return find(mid+1,R,left,right,RR(mark));
    }
    else
    {
        int t1=find(L,mid,left,mid,LL(mark));
        int t2=find(mid+1,R,mid+1,right,RR(mark));
        if(t1==-1||t2==-1) return -1;
        else return 1;
    }
}
int main()
{
    int len1,len2,T,i,d=1;
    scanf("%d",&T);
    while(T--)
    {  
        printf("Case %d:\n",d++);
        scanf("%s%s",str1,str2);
        len1=strlen(str1);
        len2=strlen(str2);
        int L=1,R=max(len1,len2);
        memset(num,0,sizeof(num));
        deal(L,R,1,len1,1,1,str1);
        deal(L,R,1,len2,1,2,str2);
        int Q;
        scanf("%d",&Q);
        while(Q--)
        {
            int dis,x,k;
            char str[5];
            scanf("%d",&x);
            if(x==1)
            {
                scanf("%d%d%s",&k,&dis,str);
                dis++;
                update(L,R,dis,1,k,str[0]);
            }
            else 
            {
                int left;
                scanf("%d",&left);
                int t=left;
                left++;
                int right=R;
                while(left<=right)
                {
                    int mid=(left+right)/2;
                    if(find(L,R,left,mid,1)==-1) right=mid-1;
                    else left=mid+1;
                }
                printf("%d\n",left-t-1);
            }
        }    
                
    }
    return 0;
}

hdu 4339 线段树+二分

标签:线段树

原文地址:http://blog.csdn.net/zxf654073270/article/details/42970375

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!