Query

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2114    Accepted Submission(s): 735

Problem Description
You are given two strings s1[0..l1], s2[0..l2] and Q - number of queries.

Your task is to answer next queries:

  1) 1 a i c - you should set i-th character in a-th string to c;

  2) 2 i - you should output the greatest j such that for all k (i<=k and k<i+j) s1[k] equals s2[k].

 
Input
The first line contains T - number of test cases (T<=25).

Next T blocks contain each test.

The first line of test contains s1.

The second line of test contains s2.

The third line of test contains Q.

Next Q lines of test contain each query:

  1) 1 a i c (a is 1 or 2, 0<=i, i<length of a-th string, 'a'<=c, c<='z')

  2) 2 i (0<=i, i<l1, i<l2)

All characters in strings are from 'a'..'z' (lowercase latin letters).

Q <= 100000.

l1, l2 <= 1000000.
 
Output
For each test output "Case t:" in a single line, where t is number of test (numbered from 1 to T).

Then for each query "2 i" output in single line one integer j.

 
Sample Input
1
aaabba
aabbaa
7
2 0
2 1
2 2
2 3
1 1 2 b
2 0
2 3
 
Sample Output
Case 1:
2
1
0
1
4
1
 
Source
 
Recommend
zhoujiaqi2010
 

题意:

给两个字符串,有两种操作。
1、改变一字符串的某个位置的一个字符。
2、询问某一位置开始的最大的连续的两串相同的字符的个数。

解题思路:
首先是简单容易理解得解法。对于题目的询问操作。如果询问的是第p位置。如果我们知道角标大于等于p位置且字符不匹配的第一个位置q。那么答案就是q-p。比如:

012345

aabbccd

aabeccd

对于p=0时。角标大于等于p且字符不匹配的第一个位置q=3。那么ans=3-0=3。

现在的问题时怎样快速维护这一信息。学习过set后知道set有一个强大的功能。

lower_bound(p)函数可以返回键值比p大的第一个值。所以这下就好办了。

开始预处理。扫描一下两个字符串。把字符不相同的位置加到set中。

对于每一个询问。只需返回lower_bound(p)-p就行了。

对于每一个修改。如果修改后的状态和原状态不同。如果原来匹配现在不匹配了。就把角标加入set。

如果原来不匹配而现在匹配了就将这个角标从set中删除。

要注意的是预处理是要将最大字符串长度+1的位置加入到set中。因为如果两个字符完全一样就悲剧了。

因为set中没有值,如果询问的话返回值就是0。于是我就这么奉献了一wa。。TT。

详细见代码:

#include <iostream>
#include<string.h>
#include<stdio.h>
#include<set>
using namespace std;
set<int> pos;
const int maxn=1000100;
char s[2][maxn];//存两个字符串
int n,m,len,len1,len2; int main()
{
int com,a,b,t,q,i,cas=1;
char c[100]; scanf("%d",&t);
while(t--)
{
printf("Case %d:\n",cas++);
scanf("%s%s",s[0],s[1]);
pos.clear();
len1=strlen(s[0]);
len2=strlen(s[1]);
len=max(len1,len2);
pos.insert(len);
for(i=0;i<len;i++)
if(s[0][i]!=s[1][i])
pos.insert(i);
scanf("%d",&q);
while(q--)
{
scanf("%d",&com);
if(com==1)
{
scanf("%d%d%s",&a,&b,c);
a--;
if(s[a][b]==s[a^1][b]&&c[0]!=s[a][b])
pos.insert(b);
else if(s[a][b]!=s[a^1][b]&&c[0]==s[a^1][b])
pos.erase(b);
s[a][b]=c[0];
}
else
{
scanf("%d",&a);
if(s[0][a]!=s[1][a])
{
printf("0\n");
continue;
}
printf("%d\n",*pos.lower_bound(a)-a);
}
}
}
return 0;
}

第二种方法要复杂一点。但要高效许多。用到的是线段树区间维护。对于线段树的一个结点。维护两个信息。

ml,mr。分别表示该结点所代表区间中。

ml从区间左端点开始算起有多少连续个字符匹配。

mr从区间右端点开始算起有多少连续个字符匹配。

要得到这两个信息很简单,直接从叶子结点往上更新。

ls为左儿子的下标。rs为右儿子的下标。

k为当前结点的下标。

L,R为当前区间的左右端点。

那么递归更新式就为:

ml[k]=ml[ls];

mr[k]=mr[rs];
 if(ml[ls]==mid-L+1)//左区间满了可以和右区间连在一起
        ml[k]+=ml[rs];
 if(mr[rs]==R-mid)//右区间满了。
        mr[k]+=mr[ls];

怎么从维护的这两个信息得到答案呢?

对于更新操作很简单。如果状态改变了。直接从叶子结点往上更新就行了。

对于询问。假设询问的位置为pos。那么pos的位置有3中可能。

1.在右连续的区间内即[R-mr[k]+1,R]。

2.在左连续的区间内即[L,L+ml[k]-1]。

3.在这两区间中间。

这三种情况依次判断

对于第一种情况。(如图p1)

ans+=R-pos+1。并且要标记下。因为右连续的话有可能与右边的区间连续。到父结点时要ans+=ml[ls]。

对于第二种情况。(如图p2)

答案是确定的。ans=L+ml[k]-pos。因为第一种情况不成立才会判断第二种情况。说明pos后面位置至少有一个不匹配。所以ans=L+ml[k]-pos。

对于第三种情况。继续往下询问就行了。因为迟早会出现1,2.两种情况。

详细见代码:

#include <iostream>
#include<string.h>
#include<stdio.h>
using namespace std; const int maxn=1000100;
int ml[maxn<<2],mr[maxn<<2];//左连续。右连续的值
char s[2][maxn];//存两个字符串
int n,m,len,ans,flag,len1,len2;
void btree(int L,int R,int k)//建树
{
int ls,rs,mid;
if(L==R)
{
if(s[0][L]==s[1][L])
ml[k]=mr[k]=1;
else
ml[k]=mr[k]=0;
return;
}
ls=k<<1;
rs=k<<1|1;
mid=(L+R)>>1;
btree(L,mid,ls);
btree(mid+1,R,rs);
ml[k]=ml[ls];
mr[k]=mr[rs];
if(ml[ls]==mid-L+1)//若右区间全满
ml[k]+=ml[rs];//可能变成的值
if(mr[rs]==R-mid)
mr[k]+=mr[ls];
}
void update(int L,int R,int x,int k)//更新x点
{
int ls,rs,mid; if(L==R)
{
if(s[0][L]==s[1][L])
ml[k]=mr[k]=1;
else
ml[k]=mr[k]=0;
return;
}
ls=k<<1;
rs=k<<1|1;
mid=(L+R)>>1;
if(x>mid)
update(mid+1,R,x,rs);
else
update(L,mid,x,ls);
ml[k]=ml[ls];
mr[k]=mr[rs];
if(ml[ls]==mid-L+1)
ml[k]+=ml[rs];
if(mr[rs]==R-mid)
mr[k]+=mr[ls];
}
void qu(int L,int R,int k,int pos)//询问pos前有多少相同字符(包括pos)
{
int ls,rs,mid;
if(L==R)
{
ans+=ml[k];
return;
}
ls=k<<1;
rs=k<<1|1;
mid=(L+R)>>1;
if(R-pos+1<=mr[k])//在右连续区间内
{
ans+=R-pos+1;
flag=1;//如果是左儿子才标记的但是。右儿子不会出现这种情况。因为点右连续区间内在父结点处就返回了。所以可以直接加标记
return;
}
if(pos-L+1<=ml[k])//在左连续区间内
{
ans=L+ml[k]-pos;
return;
}
if(pos>mid)
qu(mid+1,R,rs,pos);
else
qu(L,mid,ls,pos);
if(flag)//加上延长的区间
{
ans+=ml[rs];
flag=0;
}
}
int main()
{
int com,a,b,t,q,cas=1;
char c[100],temp; scanf("%d",&t);
while(t--)
{
printf("Case %d:\n",cas++);
scanf("%s%s",s[0]+1,s[1]+1);//字符从一开始了方便建树
len1=strlen(s[0]+1);
len2=strlen(s[1]+1);
len=max(len1,len2);//以较大的建树。开始以小的建树RE了。。TT
btree(1,len,1);
scanf("%d",&q);
while(q--)
{
scanf("%d",&com);
if(com==1)
{
scanf("%d%d%s",&a,&b,c);
a--;//2->1,1->0
b++;//由于从1开始所以要挪一下
temp=s[a][b];
s[a][b]=c[0];
if(temp==s[a^1][b]&&c[0]!=temp)
update(1,len,b,1);
else if(temp!=s[a^1][b]&&c[0]==s[a^1][b])
update(1,len,b,1);
}
else
{
scanf("%d",&a);
a++;
if(s[0][a]!=s[1][a])
{
printf("0\n");
continue;
}
flag=0;
ans=0;
qu(1,len,1,a);
printf("%d\n",ans);
}
}
}
return 0;
}

感想:做题需要的就是思维,而现在思维还不够活跃。还需要好好加油啊!

hdu 4339 Query(两种思路求解)的更多相关文章

  1. 点击页面div弹窗以外隐藏的两种思路

    在本文为大家介绍两种思路实现点击页面其它地方隐藏该div,第一种是对document的click事件绑定事件处理程序.. 第一种思路分两步 第一步:对document的click事件绑定事件处理程序, ...

  2. 使用 CUDA 进行计算优化的两种思路

    前言 本文讨论如何使用 CUDA 对代码进行并行优化,并给出不同并行思路对均值滤波的实现. 并行优化的两种思路 思路1: global 函数 在 global 函数中创建出多个块多个线程对矩阵每个元素 ...

  3. 把JSON数据载入到页面表单的两种思路(对easyui自带方法进行改进)

    #把JSON数据载入到页面表单的两种思路(对easyui自带方法进行改进) ##背景 项目中经常需要把JSON数据填充到页面表单,一开始我使用easyui自带的form load方法,觉得效率很低,经 ...

  4. C++关于数字逆序输出的两种思路,及字符串逆序输出

    C++关于数字逆序输出的两种思路,及字符串逆序输出 作者:GREATCOFFEE 发布时间:NOVEMBER 15, 2012 分类:编程的艺术 最近在跟女神一起学C++(其实我是不怀好意),然后女神 ...

  5. php 冒泡排序的两种思路以及优化

    php冒泡排序,两种思路,时间复杂度都是O(n^2),当然最优的时间复杂度就是O(n),以下说的都是正序排列(倒序的话,把内层循环的大于号换成小于号就好了) 第一种冒泡排序 思路就是把第一个数跟所有的 ...

  6. 第七篇:使用 CUDA 进行计算优化的两种思路

    前言 本文讨论如何使用 CUDA 对代码进行并行优化,并给出不同并行思路对均值滤波的实现. 并行优化的两种思路 思路1: global 函数 在 global 函数中创建出多个块多个线程对矩阵每个元素 ...

  7. Java实现快排+小坑+partition的两种思路

    在做一道剑指Offer的题的时候,有道题涉及到快排的思路,一开始就很快根据以前的思路写出了代码,但似乎有些细节不太对劲,自己拿数据试了下果然.然后折腾了下并记录下一些小坑,还有总结下划分方法parti ...

  8. WebGIS中解决使用Lucene进行兴趣点搜索排序的两种思路

    文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/. 1.背景 目前跟信息采集相关的一个项目提出了这样的一个需求:中国银行等 ...

  9. 点击页面其它地方隐藏该div的两种思路

    思路一 第一种思路分两步 第一步:对document的click事件绑定事件处理程序,使其隐藏该div 第二步:对div的click事件绑定事件处理程序,阻止事件冒泡,防止其冒泡到document,而 ...

随机推荐

  1. robotium之webview元素处理

    今天写robotium脚本发现,用uiautomatorviewer定位百度贴吧的登录框是无法定位的,如图: 明显无法定位用户名.密码输入框,无法定位元素那就无法对控件无法操作 如何定位webview ...

  2. Jquery属性选择器(同时匹配多个条件,与或非)(附样例)

    1. 前言 为了处理除了两项不符合条件外的选择,需要用到jquery选择器的多个条件匹配来处理,然后整理了一下相关的与或非的条件及其组合. 作为笔记记录. 2. 代码 <!DOCTYPE htm ...

  3. Android设计模式-观察者模式

    原文地址 http://blog.csdn.net/qq_25806863/article/details/69218968 观察者模式是一种使用频率非常高的设计模式,最常用的地方就是订阅-发布系统. ...

  4. vue系列之生命周期

    代码: <body> <div id="app"> {{message}} </div> <script type="text/ ...

  5. LeetCode(57):插入区间

    Hard! 题目描述: 给出一个无重叠的 ,按照区间起始端点排序的区间列表. 在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间). 示例 1: 输入: i ...

  6. iOS学习笔记之Block

    写在前面 学习iOS开发的过程中,在很多场合都遇到了Block.说实话,虽然自己依葫芦画瓢的将Block"拿来"用着,但这种"拿来主义"与学习时应持有的探索精神 ...

  7. 步步为营-59-svn简介

    说明:版本控制器Svn的使用,安装教程不再多说 VisualSVN-Server--项目经理 TortoiseSVN--右击的时候显示 VisualSVN-- visual studio中使用 1 搭 ...

  8. 存储过程+Jquery+WebService实现三级联动:

    首先看一下数据库的设计:

  9. struts2使用拦截器完成登陆显示用户信息操作和Struts2的国际化

    其实学习框架,就是为了可以很好的很快的完成我们的需求,而学习struts2只是为了替代之前用的servlet这一层,框架使开发更加简单,所以作为一个小菜鸟,特别感谢那些超级无敌变态开发的框架供我们使用 ...

  10. [转] SSO单点登录原理和流程分析

    WEB的登录那些事#### 说道账户登录和注册,其实我们每天都在亲身感受着,像微博.知乎还有简书等等.我们总是需要定期的去重新登录一下,对于这种认证机制,我们都能说出来两个名词,Cookie.Sess ...