HDU-4339 Query(树状数组+二分)

点击打开题目链接


题意:给出长度分别为l1和l2的字符串s1和s2,要求进行k次操作,每次操作输入的第一个数如果是1,接着就输入两个整数a,i和一个字符c,要求将第a个字符串的下标为i的字符换位c。如果输入的第一个数是2,紧接着就输入一个数字i,要求找到一个最大的数字j,使得在区间[i,j)中两个字符串的字符相等。

分析:之前看到题目给了10s直接暴力求解TLE了。。。后来从别人的题解中受到了启发,需要用到树状数组,这样能节省不少时间开销。用一个数组保存状态(如果s1[i]=s2[i]就为0,否则为1),每次进行1操作时更新树状数组的数据,而进行2操作时用二分找到满足sum(j)-sum(i)=0的最大j就可以了。这道题又加深了我对树状数组的理解。


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1000005;
char s1[maxn],s2[maxn];
int c[maxn];
int k,len;
int lowbit(int x)
{
    return x&-x;
}
void update(int i,int x)//更新树状数组的数据
{
    for(;i<=len;i+=lowbit(i))
        c[i]+=x;
}
int sum(int i)//求和操作
{
    int sum=0;
    for(;i>0;i-=lowbit(i))
        sum+=c[i];
    return sum;
}
int Search(int i)//二分查找
{
    int left=i,right=len,mid=0,ans=i-1;
    while(left<=right)
    {
        mid=(left+right)/2;
        int x=sum(mid)-sum(i-1);
        //cout<<"mid="<<mid<<",sum(mid)="<<sum(mid)<<",sum(i-1)="<<sum(i-1)<<endl;
        if(x==0) { ans=mid; left=mid+1; }
        else right=mid-1;
    }
    return ans-i+1;
}
int main()
{
    int T;
    cin>>T;
    int cnt=1;
    while(T--)
    {
        memset(c,0,sizeof c);
        printf("Case %d:\n",cnt++);
        scanf("%s%s",s1,s2);
        scanf("%d",&k);
        int len1=strlen(s1),len2=strlen(s2);
        len=min(len1,len2);
        for(int i=0;i<len;i++)
        {
            if(s1[i]!=s2[i])
            {
                update(i+1,1);
            }
        }
        /*for(int i=1;i<=len;i++)
            printf("sum%d=%d  ",i,sum(i));*/
        while(k--)
        {
            int t;
            scanf("%d",&t);
            if(t==1)
            {
                int a,i;
                char ch;
                scanf("%d %d %c",&a,&i,&ch);
                bool flag=(s1[i]==s2[i]);
                if(a==1) s1[i]=ch;
                else s2[i]=ch;
                if(flag&&s1[i]!=s2[i])
                {
                    update(i+1,1);
                }
                if((!flag)&&s1[i]==s2[i])
                {
                    update(i+1,-1);
                }
            }
            else
            {
                int i;
                scanf("%d",&i);
                int ans=Search(i+1);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值