CF438D The Child and Sequence

原题链接:http://codeforces.com/problemset/problem/438/D

The Child and Sequence

At the children’s day, the child came to Picks’s house, and messed his house up. Picks was angry at him. A lot of important things were lost, in particular the favorite sequence of Picks.

Fortunately, Picks remembers how to repair the sequence. Initially he should create an integer array a[1],a[2],,a[n] a [ 1 ] ,   a [ 2 ] ,   ⋯ ,   a [ n ] . Then he should perform a sequence of m operations. An operation can be one of the following:

Print operation l,r l ,   r . Picks should write down the value of ri=la[i] ∑ i = l r a [ i ] .
Modulo operation l,r,x l ,   r ,   x . Picks should perform assignment a[i]=a[i] mod x a [ i ]   =   a [ i ]   m o d   x for each i (lir) i   ( l   ≤   i   ≤   r ) .
Set operation k,x k ,   x . Picks should set the value of a[k] a [ k ] to x x (in other words perform an assignment a[k]=x).
Can you help Picks to perform the whole sequence of operations?

Input

The first line of input contains two integer: n,m(1n,m105) n ,   m ( 1   ≤   n ,   m   ≤   10 5 ) . The second line contains n integers, separated by space: a[1],a[2],...,a[n](1a[i]109) a [ 1 ] ,   a [ 2 ] ,   . . . ,   a [ n ] ( 1   ≤   a [ i ]   ≤   10 9 ) — initial value of array elements.

Each of the next m lines begins with a number type (type{1,2,3}) ( t y p e ∈ { 1 , 2 , 3 } ) .

If type =  1 1 , there will be two integers more in the line: l,r(1lrn), which correspond the operation 1.
If type =  2 2 , there will be three integers more in the line: l,r,x(1lrn;1x109), which correspond the operation 2.
If type =  3 3 , there will be two integers more in the line: k,x(1kn;1x109), which correspond the operation 3.

Output

For each operation 1, please print a line containing the answer. Notice that the answer may exceed the 32-bit integer.

Examples
input

5 5
1 2 3 4 5
2 3 5 4
3 3 5
1 2 5
2 1 3 3
1 1 3

output

8
5

input

10 10
6 9 6 7 6 1 10 10 9 5
1 3 9
2 7 10 9
2 5 10 8
1 4 7
3 3 7
2 7 9 9
1 2 4
1 6 6
1 5 9
3 1 10

output

49
15
23
1
9

Note

Consider the first testcase:

At first, a={1,2,3,4,5} a   =   { 1 ,   2 ,   3 ,   4 ,   5 } .
After operation 1,a={1,2,3,0,1} 1 , a   =   { 1 ,   2 ,   3 ,   0 ,   1 } .
After operation 2,a={1,2,5,0,1} 2 , a   =   { 1 ,   2 ,   5 ,   0 ,   1 } .
At operation 3,2+5+0+1=8 3 , 2   +   5   +   0   +   1   =   8 .
After operation 4,a={1,2,2,0,1} 4 , a   =   { 1 ,   2 ,   2 ,   0 ,   1 } .
At operation 5,1+2+2=5 5 , 1   +   2   +   2   =   5 .

题解

如果取模生效的话,被%的数至少会变成原来的一半,所以我们统计一下区间最大值,如果 maxmod m a x ≥ m o d 就暴力递归下去取模,最多取 log2max l o g 2 m a x 次。因为修改是单点的,所以对复杂度的影响不大,最终复杂度为 O(n log2n log2max) O ( n   l o g 2 n   l o g 2 m a x )

代码
#include<bits/stdc++.h>
#define ll long long
#define ls v<<1
#define rs ls|1
using namespace std;
const int M=4e5+5;
ll que[M],mx[M],sum[M],n,m;
void up(int v){mx[v]=max(mx[ls],mx[rs]),sum[v]=sum[ls]+sum[rs];}
void build(int v,int le,int ri)
{
    if(le==ri){mx[v]=sum[v]=que[le];return;}
    int mid=le+ri>>1;
    build(ls,le,mid);build(rs,mid+1,ri);
    up(v);
}
ll ask(int v,int le,int ri,int lb,int rb)
{
    if(lb<=le&&ri<=rb)return sum[v];
    int mid=le+ri>>1;ll ans=0;
    if(lb<=mid)ans=ask(ls,le,mid,lb,rb);
    if(mid<rb)ans+=ask(rs,mid+1,ri,lb,rb);
    return ans;
}
void mod(int v,int le,int ri,int lb,int rb,int d)
{
    if(le==ri){mx[v]=sum[v]=mx[v]%d;return;}
    int mid=le+ri>>1;
    if(lb<=mid&&mx[ls]>=d)mod(ls,le,mid,lb,rb,d);
    if(mid<rb&&mx[rs]>=d)mod(rs,mid+1,ri,lb,rb,d);
    up(v);
}
void alter(int v,int le,int ri,int pos,int d)
{
    if(le==ri){sum[v]=mx[v]=d;return;}
    int mid=le+ri>>1;
    if(pos<=mid)alter(ls,le,mid,pos,d);
    else alter(rs,mid+1,ri,pos,d);
    up(v);
}
void in(){scanf("%d%d",&n,&m);for(int i=1;i<=n;++i)scanf("%d",&que[i]);}
void ac()
{
    build(1,1,n);int a,b,c,op;
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&op,&a,&b);
        if(op==1)printf("%I64d\n",ask(1,1,n,a,b));
        else if(op==2)scanf("%d",&c),mod(1,1,n,a,b,c);
        else alter(1,1,n,a,b);
    }
}
int main(){in();ac();}
<think>好的,用户现在想要取消通过SetParent设置的窗体嵌套效果。之前我已经详细介绍了如何使用Win32 API的SetParent函数在C#中实现窗体嵌套,并提到了需要注意的关键问题。现在用户需要撤销这个操作,可能需要将子窗体恢复为独立窗口,并处理相关的样式和消息循环问题。 首先,我需要回想一下SetParent的作用。SetParent函数将子窗体的父窗口设置为指定的句柄,从而建立父子关系。要取消这个效果,可能需要将父窗口句柄设置为NULL或桌面窗口的句柄,即HWND_MESSAGE或HWND_DESKTOP,具体取决于情况。根据MSDN文档,将父窗口设置为NULL可能不会完全恢复所有样式,因此可能需要手动调整窗口样式。 接下来,用户的问题可能涉及如何正确恢复子窗体的原始样式。之前在使用SetParent时,修改了窗口的样式为WS_CHILD,现在需要恢复为WS_OVERLAPPEDWINDOW或其他原始样式。此外,还需要处理窗体边框的恢复,因为在嵌套时可能去掉了边框(FormBorderStyle.None)。同时,布局调整,比如Dock属性设置为Fill,可能需要重置为None或其他适当的值。 另一个需要注意的问题是跨进程窗体的情况。如果子窗体是外部进程的窗口(如记事本),在取消SetParent后,可能需要特别处理,比如发送关闭消息或正确释放资源。此外,焦点和消息循环的问题也需要考虑,确保子窗体能够接收用户输入并正确响应。 用户可能遇到的常见问题包括窗体无法正确显示、样式未恢复、输入无响应等。需要指导用户如何逐步撤销SetParent的影响,并处理潜在的内存泄漏或资源未释放的问题。例如,在跨进程嵌入的情况下,直接关闭父窗口可能导致子进程残留,因此需要正确关闭子窗口。 此外,还需要比较不同的方法,比如使用SetParent与原生容器控件(如Panel)的差异,帮助用户理解在何种情况下选择哪种方法更合适。如果用户只是暂时需要取消嵌套,可能需要临时调整,而如果是永久性的,则需要更彻底的恢复步骤。 最后,应该提醒用户进行测试,确保在取消SetParent后,窗体行为符合预期,特别是在处理DPI缩放和布局时可能出现的问题。可能需要建议用户检查窗体的位置、大小、样式以及消息处理是否正常,并提供常见问题的排查步骤,例如黑框现象或焦点丢失的解决方法。</think>以下是取消`SetParent`效果的完整解决方案,包含关键步骤和注意事项: --- ### **一、基础恢复方法** ```csharp // 引入必要API [DllImport("user32.dll")] static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent); [DllImport("user32.dll")] static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong); const int GWL_STYLE = -16; const int WS_OVERLAPPEDWINDOW = 0x00CF0000; // 标准窗口样式 void RestoreWindow(Form childForm) { // 1.重置父窗口为桌面 SetParent(childForm.Handle, IntPtr.Zero); // 参数二设为IntPtr.Zero // 2.恢复窗口样式(关键操作) SetWindowLong(childForm.Handle, GWL_STYLE, WS_OVERLAPPEDWINDOW); // 3.恢复窗体外观 childForm.FormBorderStyle = FormBorderStyle.Sizable; childForm.Dock = DockStyle.None; // 4.强制刷新窗口 childForm.Refresh(); } ``` --- ### **二、跨进程窗口的特殊处理** ```csharp // 针对外部程序窗口的完全解除 void FullReleaseExternalWindow(IntPtr hWnd) { // 1.解除父子关系 SetParent(hWnd, IntPtr.Zero); // 2.恢复窗口样式 const int WS_VISIBLE = 0x10000000; SetWindowLong(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE); // 3.确保窗口可见 ShowWindow(hWnd, 1); // SW_SHOWNORMAL // 4.发送重绘命令 RedrawWindow(hWnd, IntPtr.Zero, IntPtr.Zero, 0x85); // RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW } ``` --- ### **三、必须处理的恢复细节** #### 1. **样式重置规范** | 样式类型 | 恢复值 | 对应常量值 | |----------------|--------------------------|------------------| | 窗口风格 | WS_OVERLAPPEDWINDOW | 0x00CF0000 | | 扩展样式 | WS_EX_APPWINDOW | 0x00040000 | | 可见性 | WS_VISIBLE | 0x10000000 | ```csharp // 完整样式恢复示例 SetWindowLong(hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE); SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW); ``` #### 2. **Dock布局重置** ```csharp // 清除自动布局设置 childForm.Dock = DockStyle.None; childForm.Size = new Size(800, 600); // 设置合理默认尺寸 childForm.StartPosition = FormStartPosition.WindowsDefaultLocation; ``` #### 3. **焦点系统恢复** ```csharp // 强制激活窗口 [DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr hWnd); SetForegroundWindow(childForm.Handle); ``` --- ### **四、内存管理规范** | 操作类型 | 标准处理流程 | |----------------|------------------------------------------------------------------------------| | 同进程窗口 | 1.解除父子关系<br>2.恢复样式<br>3.调用`childForm.Show()` | | 跨进程窗口 | 1.解除父子关系<br>2.恢复样式<br>3.发送`WM_SYSCOMMAND`恢复窗口框架 | | 嵌入式控件 | 额外需要调用`DestroyWindow`(仅限Native控件) | --- ### **五、典型问题解决方案** #### 1. **窗口变透明** ```csharp // 修复分层窗口问题 SetWindowLong(hWnd, GWL_EXSTYLE, GetWindowLong(hWnd, GWL_EXSTYLE) & ~0x80000); // 清除WS_EX_LAYERED ``` #### 2. **窗口位置异常** ```csharp // 重置窗口位置 SetWindowPos(hWnd, IntPtr.Zero, Screen.PrimaryScreen.WorkingArea.Left + 100, Screen.PrimaryScreen.WorkingArea.Top + 100, 0, 0, 0x2001); // SWP_NOSIZE | SWP_NOZORDER ``` #### 3. **输入无响应** ```csharp // 重建消息循环 childForm.Close(); childForm = new OriginalForm(); // 重新实例化窗体 childForm.Show(); ``` --- ### **六、最佳实践建议** 1. **恢复顺序原则**: ``` 解除父子关系 → 恢复窗口样式 → 重置布局属性 → 触发重绘 ``` 2. **跨进程恢复黄金法则**: - 先解除父子关系再调整样式 - 必须显式设置窗口可见性 - 建议使用`SetWindowPos`而不是直接设置位置属性 3. **诊断工具推荐**: - 使用Spy++验证窗口层级 - 通过`GetWindowLong`检查实际样式值 - 使用`GetWindowRect`确认窗口坐标 --- ### **七、与原生容器方案对比** ```mermaid sequenceDiagram participant A as SetParent方案 participant B as Panel容器方案 A->>B: 解除操作复杂度 Note over A,B: SetParent需要手动恢复7+项属性 B->>A: 恢复可靠性 Note over A,B: Panel方案自动管理子控件生命周期 ``` > 📌 重要提示:如果原窗体已被销毁,需要重新创建实例。建议在调用`SetParent`时保留原始样式备份: > ```csharp > // 备份原始样式 > int originalStyle = GetWindowLong(hWnd, GWL_STYLE); > int originalExStyle = GetWindowLong(hWnd, GWL_EXSTYLE); > ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShadyPi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值